I'm having some trouble with C++: I have a class Primitive, it contains a member variable of an abstract buffer class..
Concrete buffer classes exist in many different forms for many different vertex types.. point-colour-normal, point-texcoord-normal, point-normal, point, etc.
I need to be able to add any type of vertex to a buffer held by classes that derive from primitive, for example quadsets, tri-lists, etc.
class Buffer {
//...
template<class T>
virtual void Add(const T&) = 0; // nope! Not compilable
virtual void Add(boost::any&) = 0; // I have been told no boost allowed either..
}
template<class T>
TypedBuffer : public Buffer {
//..
public:
std::vector<T> buffer;
public:
virtual void Add( const T& elem ) { buffer.push_back( elem ); }
}
class Primitive {
protected:
Buffer vertices;
public:
// How can I allow this to happen? \/
virtual void AddVert( const vec3& v) { vertices.Add( v ); }
}
class QuadSet : public Primitive { /*QuadSet Specifics..*/ }
void main(){
QuadSet q;
q.Add( COLOURED_VERT(vec3(1, 2, 3), vec3(0.5,0.5,0.5) ) );
}
Please Help!
When facing a similar problem, I ended up using type eraser. However in my example it requires to use something like reinterpret_cast:
class Buffer {
virtual void Add(const void*) = 0;
};
template <typename T>
class TypedBuffer: Buffer {
virtual void Add(const void* e) { buffer.push_back(*static_cast<T*>(e)); }
};
class Primitive {
virtual void AddVert(const vec3& v) { vertices.Add(reinterpret_cast<const void*>(&v)); }
};
Related
I have an ISerializable interface with pure virtual read and write functions. I also have a List<T> class. So, my question is: can I inherit my List<T> from ISerializable only if T is also inherit from ISerializable?
usage example:
#include <array>
#include <iostream>
class ISerializable
{
public:
virtual void read(std::istream& stream) = 0;
virtual void write(std::ostream& stream) = 0;
};
class A : public ISerializable {
public:
void read(std::istream& stream) override {}
void write(std::ostream& stream) override {}
};
class B {};
template<typename T>
class List : public ISerializable
{
public:
void read(std::istream& stream) override
{
for (int i = 0; i < items.size(); i++)
{
items[i].read(stream);
}
}
void write(std::ostream& stream) override
{
for (int i = 0; i < items.size(); i++)
{
items[i].write(stream);
}
}
private:
std::array<T, 10> items;
};
int main()
{
List<A> list_a;
//List<B> list_b; <- error here
}
You can indeed set up something like that up in C++20.
template<typename T>
class List : public ListCommon<T> {
};
template<std::derived_from<ISerializable> S>
class List<S> : public ListCommon<S>, public ISerializable {
// Implement the serialization
};
The specialization for a serialziable type is only viable with the added constraint of the type being derived from ISerializable (checked with the standard std::derived_from concept).
ListCommon is where I would place the common implementation details to avoid repeating them upon specialization.
Ok, this solution fits if you already have a lot of classes that you don't really want to refactor and/or duplicate. The disadvantage here is that IDE will not be able to assist you sometimes. However, since it implies one of main features of concepts, it is still legal. Just be careful!
Here we have an interface that explicitly requires some functions to be implemented and a concept that also requires same functions to be implemented. Prefer interface over the concept! If you inherit interface, IDE will assist you in function overloading. Concept is needed if you want to use interface as a parameter type later (see utility class example). This is an example of duck typing.
class ISerializable
{
public:
virtual void write_to_stream(std::ostream& stream) const = 0;
virtual void read_from_stream(std::istream& stream) = 0;
};
template<typename T>
concept ImplicitlySerializable = requires(const T a1, T a2, std::ostream os, std::istream is)
{
a1.write_to_stream(os);
a2.read_from_stream(is);
};
template<typename T>
concept Serializable = std::derived_from<T, ISerializable> || ImplicitlySerializable<T>;
Some utility functions to handle any object that match concept
class StreamUtils
{
public:
template<Serializable T>
static void write(std::ostream& stream, const T& value)
{
value.write_to_stream(stream);
}
template<Serializable T>
static void read(std::istream& stream, T& to)
{
to.read_from_stream(stream);
}
};
Usage example:
// Interface usage
class Animal : public ISerializable
{
void write_to_stream(std::ostream& stream) override
{
// serialization code here
}
void read_from_stream(std::istream& stream) override
{
// deserialization code here
}
}
// Concept usage
template<typename T>
class List
{
void write_to_stream(std::ostream& stream) const requires Serializable<T>
{
// serialization code here
}
void read_from_stream(std::istream& stream) requires Serializable<T>
{
// deserialization code here
}
{
int main()
{
std::ofstream file("my_file.bin", std::ios::out | std::ios:binary);
StreamUtils::write(file, Animal());
StreamUtils::write(file, List<Animal>());
}
I have a class TypedNode to store some data:
template <typename Type>
class TypedNode {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }
private:
Type data_;
};
Then I can use it:
int main() {
TypedNode<int> int_node;
TypedNode<double> double_node;
TypedNode<Vector3d> vector3_node;
int_node.SetNodeData(1);
double_node.SetNodeData(2.3);
vector3_node.SetNodeData(Vector3d(4,5,6));;
}
But I want to define a function to access then:
void Access(std::list<TypedNode> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}
The list needs a concrete class, But I need to store any type of nodes.
Some I changed the code of Node:
class NodeBase {
public:
NodeBase() {}
};
template <typename Type>
class TypedNode : NodeBase {
public:
TypedNode() {}
void SetNodeData(Type data) { data_ = data; }
Type GetNodeData() { return data_; }
private:
Type data_;
};
void Access(std::list<NodeBase> node_list) {
for (auto node : node_list) {
node.GetNodeData();
// if it is an integer, do one thing
// if it is a double, do another
}
}
But the Access() function can only call the methods of Base class.
Despite every derived class have one same name interface SetNodeData, They have a different type. So they are different. They cannot override one same interface in the Base class.
What can I do?
==============================================================
This is my solution:
#include <list>
enum NodeType {
kInt,
kDouble,
kVector3,
};
class NodeBase {
public:
NodeBase() {}
virtual int GetDataInt();
virtual double GetDataDouble();
virtual Vector3 GetDataVector3();
NodeType type() const { return type_; }
protected:
void set_type(NodeType type) { type_ = type; }
private:
NodeType type_;
};
class NodeInt : NodeBase {
public:
NodeInt() { set_type(kInt); }
int GetDataInt() override { return data_; }
double GetDataDouble() override { check(false) << "error"; }
Vector3 GetDataVector3() override { check(false) << "error"; }
private:
int data_;
};
class NodeDouble : NodeBase {
public:
NodeDouble() { set_type(kDouble); }
int GetDataInt() override { check(false) << "error"; }
double GetDataDouble() override { return data_; }
Vector3 GetDataVector3() override { check(false) << "error"; }
private:
double data_;
};
void Access(const std::list<NodeBase>& node_list) {
for (auto node : node_list) {
switch (node.type()) {
case kInt: {
int data = node.GetDataInt();
// do something about int
break;
}
case kDouble: {
double data = node.GetDataDouble();
// do something about double
break;
}
case kVector3: {
Vector3 data = node.GetDataVector3();
// do something about Vector3
break;
}
}
}
}
Your TypedNode template provides no apparent value, it is just a getter and a setter of encapsulated data so it is better to eliminate it for simplicity. What you seem to need is a type that can be int, double or Vector3d so those can be held in same container. For that there is std::variant in C++17. People with substandard compilers can use Boost.Variant that is basically same, just works with C++98 too.
#include <variant>
struct Vector3d {int x, y, z;};
using Node = std::variant<int,double,Vector3d>;
Sure, you can have std::variant<TypedNode<int>,TypedNode<double>,TypedNode<Vector3d>> when there is some vital functionality in it. Posted TypedNode had no functionality, other but more bloat to type.
For accessing variant using same interface there are several ways. For example it can be done using a visitor. Here is a visitor NodeOutput for ostream output of every type in Node.
#include <iostream>
struct NodeOutput {
std::ostream& os_;
NodeOutput(std::ostream& os) : os_{os} {}
void operator()(Vector3d const& v3)
{
os_ << "Vector3d (" << v3.x <<", "<< v3.y <<", "<< v3.z <<")\n";
}
void operator()(double const& d) {os_ << "Double " << d <<"\n";}
void operator()(int const& i) {os_ << "Int " << i <<"\n";}
};
Using such visitor we can write operator<< for Node:
std::ostream& operator<< (std::ostream& os, Node const& v) {
std::visit(NodeOutput{os}, v);
return os;
}
Trying it out. The std::list is rarely used container so here it is replaced with std::vector for simplicity, but it will work similarly with other containers.
#include<vector>
int main()
{
std::vector<Node> nodes;
nodes.emplace_back(42);
nodes.emplace_back(6.66);
nodes.emplace_back(Vector3d{3,2,1});
for (auto& n: nodes) {std::cout << n;}
}
Output:
Int 42
Double 6.66
Vector3d (3, 2, 1)
From what i understand, you basically want to access the overridden functions of the NodeBase. You can still do that with templates. I am not going to suggest code changes on your design because i assume that you oversimplified this to give us an idea of what you want your code to do.
With that said, let's assume that NodeBase class is the base class for NodeInt and NoteDouble. and it looks something like this (slightly simplified compared to yours).
class NodeBase
{
public:
...
virtual void DoSomething()
...
};
class NodeInt : public NodeBase
{
public:
...
virtual void DoSomething() //overridden
{
}
...
};
class NodeDouble : public NodeBase
{
public:
...
void DoSomething()//overriden
{
}
...
};
Let's also assume that our Access function looks like;
template<typename Type, typename A>
void Access(std::list<TypedNode<Type>, A> node_list)
{
for (auto node : node_list)
{
node.DoSomething();
}
}
Note that our Access function can now take any type of list containingTypeNode because of TypedNode<Type>
The job of the Access function is just to call the DoSomething. it shouldn't care what type it is. and it should be deduced based on what to call depending on what we pass as an argument to the Access call.
if a list passed to Access is a type <TypedNode<NodeBase> you
want each node to call, NodeBase::DoSomething();
if a list passed to Access is a type <TypedNode<NodeInt> you want
each node to call, NodeInt::DoSomething();
if a list passed to Access is a type <TypedNode<NodeDouble> you
want each node to call, NodeInt::DoSomething();
To do this, first Instead of inheriting from Base class, lets inherit from a parameterized template argument.
template<typename Type>
class TypedNode : public Type
Next, we want to declare and define the DoSomething function for our TypedNode class.
template<typename Type>
class TypedNode : public Type
{
...
void DoSomething();
...
};
template<typename Type>
inline void TypedNode<Type>::DoSomething()
{
Type::DoSomething();//this is where the magic happens.
}
Notice the Type::DoSomething(); this will allow us to call DoSomething() function of the Generic Base class. One thing to pay attention to is that when we initializing an object using template arguments, the class that is used in the template argument initialization has to have a class member named DoSomething otherwise during compilation we will get an error.
for example;
TypedNode<int> intNode; //wont work because int doesnt have a member DoSomething.
TypeNode<NodeBase> baseNode; //fine.
TypeNode<NodeInt> intNode2; //fine
finally, the main code that produces the outcomes for us.
int main()
{
std::list<TypedNode<NodeBase>> baseNodeList;
std::list<TypedNode<NodeInt>> intNodeList;
std::list<TypedNode<NodeDouble>> DoubleNodeList;
TypedNode<NodeBase> baseNode;
TypedNode<NodeInt> intNode;
TypedNode<NodeDouble> doubleNode;
baseNodeList.push_back(baseNode);
intNodeList.push_back(intNode);
DoubleNodeList.push_back(doubleNode);
Access(baseNodeList);
Access(intNodeList);
Access(DoubleNodeList);
return 0;
}
here is the full code https://ideone.com/2jEmBO
I am trying to solve a programming problem that consists of an object (call it Diagram), that contains several parameters. Each parameter (the Parameter class) can be one of several types: int, double, complex, string - to name a few.
So my first instinct was to define my Diagram class as having a vector of template parameters, which would look like this.
class Diagram
{
private:
std::vector<Parameter<T> > v;
};
This doesn't compile, and I understand why. So, based on the recommendations on this page How to declare data members that are objects of any type in a class, I modified my code to look like:
class ParameterBase
{
public:
virtual void setValue() = 0;
virtual ~ParameterBase() { }
};
template <typename T>
class Parameter : public ParameterBase
{
public:
void setValue() // I want this to be
// void setValue(const T & val)
{
// I want this to be
// value = val;
}
private:
T value;
};
class Diagram
{
public:
std::vector<ParameterBase *> v;
int type;
};
I'm having trouble figuring out how to call the setValue function with an appropriate templated parameter. It is not possible to have a templated parameter in the ParameterBase abstract base class. Any help is greatly appreciated.
P.S. I don't have the flexibility to use boost::any.
You got very close. I added a few bits because they're handy
class ParameterBase
{
public:
virtual ~ParameterBase() {}
template<class T> const T& get() const; //to be implimented after Parameter
template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};
template <typename T>
class Parameter : public ParameterBase
{
public:
Parameter(const T& rhs) :value(rhs) {}
const T& get() const {return value;}
void setValue(const T& rhs) {value=rhs;}
private:
T value;
};
//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }
class Diagram
{
public:
std::vector<ParameterBase*> v;
int type;
};
Diagram can then do stuff like these:
Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception
It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagram have the correct destructor, and make it non-copy-constructable, and non-copy-assignable.
The bellow implementation uses a few C++11 features but you will be
able to pick them apart.
#include <vector>
#include <memory>
class Parameter
{
private:
class ParameterBase {
public:
virtual ~ParameterBase() {}
virtual ParameterBase* copy() = 0;
virtual void foo() = 0;
};
template <typename T>
class ParameterModel : public ParameterBase {
public:
// take by value so we simply move twice, if movable
ParameterModel(const T& t) : t(t) {}
ParameterModel(T&& t) : t(t) {}
void foo() { t.foo(); }
ParameterModel* copy() { return new ParameterModel(*this); }
private:
T t;
};
public:
template <typename T>
Parameter(T&& t)
: pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}
// Movable and Copyable only
Parameter(Parameter&&) = default;
Parameter& operator=(Parameter&&) = default;
Parameter(const Parameter& other) : pp(other.pp->copy()) {};
Parameter operator=(const Parameter& other) {
pp.reset(other.pp->copy());
return *this;
};
// members
void foo() { pp->foo(); }
private:
std::unique_ptr<ParameterBase> pp;
};
class Diagram
{
public:
std::vector<Parameter> v;
int type;
};
struct X {
void foo() {}
};
struct Y {
void foo() {}
};
int main()
{
Diagram d;
d.v.emplace_back(X()); // int
// parameters are copyable and can be reassigned even with different
// impls
Parameter p = d.v.back();
Parameter other((Y()));
other = p;
return 0;
}
What does this code do? It hides the fact that we use inheritance to
implement parameters from our users. All they should need to know is
that we require a member function called foo. These requirements are
expressed in our ParameterBase. You need to identify these
requirements and add the to ParameterBase. This is basically a more
restrictive boost::any.
It is also quite close to what is described in Sean Parent's value semantics talk.
I have the following class:
class ValueSetter: public IValueSetter
{
public:
explicit ValueSetter(CContainer* container)
: _container(container)
{
}
virtual void operator()(const int value, const int index) const
{
_container->values[index].value.i = value;
}
virtual void operator()(const double value, const int index) const
{
_container->values[index].value.d = value;
}
virtual void operator()(const std::string& value, const int index) const
{
...
_container->values[index].value.s = _strdup(value.c_str());
}
private:
CContainer* _container;
};
This class operates on CContainer which stores its data in a buffer of unions. I pass ValueSetter to a Container class which has no knowledge of CContainer. Indeed, in the future I'm hoping that CContainer (which I received via a C API) will disappear and that the values are instead organised in a std::vector or std::list. My Container's interface shouldn't need to change because of this and shouldn't care about how the data is stored in memory.
With this in mind, I'd prefer instead something roughly along these lines:
class IntValueSetter: public IIntValueSetter
{
public:
explicit IntValueSetter(Container* container)
: _container(container)
{
}
virtual void operator()(const int value, const int index) const
{
_container->values[index].value.i = value;
}
private:
CContainer_3* _container;
}
or:
class IntValueSetter: public IIntValueSetter
{
public:
explicit IntValueSetter(std::vector<int> values)
: _values(values)
{
}
...
}
but I'd need to be able to use them as follows:
ValueSetter<int> valueSetter;
instead of
IntValueSetter valueSetter;
How can I do this?
Just do the obvious. There's no requirement that a template specialization have anything in common with another specialization or with the original template. So:
class IIntValueSetter {
};
template <class Ty> class ValueSetter; // declared but not defined
template <>
class ValueSetter<int> : public IIntValueSetter {
// whatever
};
ValueSetter<int> vsi;
If I get you right, you just need to write a class template:
template <typename T>
class ValueSetter
{
public:
explicit ValueSetter(std::vector<T> values): _values(values)
{
}
virtual void operator()(const T value, const int index) const
{
_container->values[index].value.i = value;
}
// etc.
};
I guess I'm looking for something like this. I've only implemented for int below, but each type would get its own interface class and implementation class. I'd love to hear your comments on this approach!
template<typename V>
class IValueSetter
{
public:
};
template<>
class IValueSetter<std::string>
{
public:
virtual void operator()(const std::string& value, int index) const = 0;
};
template<typename V>
class ValueSetter
{
};
template<>
class ValueSetter<std::string>: public IValueSetter<std::string>
{
public:
explicit ValueSetter2(CContainer* container)
: _container(container)
{
}
void operator()(const std::string& value, int index) const
{
_container->values[index].value.s = _strdup(value.c_str());
}
private:
CContainer* _container;
};
template<>
class NewValueSetter<std::string>: public IValueSetter<std::string>
{
public:
explicit NewValueSetter(std::shared_ptr<std::list<std::string>> values)
: _values(values)
{
}
void operator()(const std::string& value, int index) const
{
(*values)[index] = value;
}
private:
std::shared_ptr<std::list<std::string>> _values;
};
Suppose I have the following classes:
class BaseObject {
public:
virtual int getSomeCommonProperty();
};
class Object1: public BaseObject {
public:
virtual int getSomeCommonProperty(); // optional
int getSomeSpecificProperty();
};
class BaseCollection {
public:
virtual void someCommonTask();
};
class Collection1: public BaseCollection {
public:
virtual void someCommonTask(); // optional
void someSpecificTask();
};
Each collection, derived from BaseCollection, deals with a specific object type (and only one type). But BaseCollection should be able to perform some tasks that are common to all objects, using only common object properties in BaseObject.
Currently, I have potentially three solutions in mind:
1) Store the objects list in BaseCollection, such as:
class BaseCollection {
vector<BaseObject*> objects;
};
The problem with this solution is that when I need to perform object-specific task in Collection1, I need a dynamic_cast<>, because I don't want to use virtual inherance for specific properties, applying to only one type of object. Considering that dynamic_cast<> could potentially get called millions of time per second, this seems an issue for a performance critical application.
2) Store the objects list in Collection1, such as:
class Collection1: public BaseCollection {
vector<Object1*> objects;
}
But then I need some way to access this object list in BaseCollection, to be able to perform some common tasks on them, ideally through an iterator. I would need to create a function that return a vector for the BaseCollection, but again, this does not seem very efficient, because the only way to do that is to create a new vector (potentially containing thousands of objects)...
3) Store the objects list in BaseCollection AND Collection1:
class BaseCollection {
public:
void someCommonTask(); // Use baseObjects
virtual void addObject() = 0;
protected:
vector<BaseObject*> baseObjects;
};
class Collection1: public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
}
Where the two lists actually contain the same objects. Is that as ugly as it sounds like?
I am looking for the right/correct/best design pattern for this type of problem and none of the 3 solutions exposed above really satisfies me...
Maybe it is possible to solve that problem with templates, but then I don't see a way to store a list of polymorphic collections like this:
vector<BaseCollection*> collections;
You can store all your objects of base and derived classes in one collection through the base class (smart) pointer. Using visitor design pattern and double dispatch mechanism you can call a function only on objects of a specific type without having to expose that function in the base class interface. For example:
#include <boost/intrusive_ptr.hpp>
#include <boost/bind.hpp>
#include <vector>
#include <algorithm>
#include <stdio.h>
struct Visitor { // Visitor design patter
virtual void visit(struct BaseObject&) {}
virtual void visit(struct Object1&) {}
};
struct BaseObject {
unsigned ref_count_; // intrusive_ptr support
BaseObject() : ref_count_() {}
virtual ~BaseObject() {}
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
void intrusive_ptr_add_ref(BaseObject* p) { // intrusive_ptr support
++p->ref_count_;
}
void intrusive_ptr_release(BaseObject* p) { // intrusive_ptr support
if(!--p->ref_count_)
delete p;
}
struct Object1 : BaseObject {
virtual void accept(Visitor& v) { v.visit(*this); } // Visitor's double dispatch
virtual void getSomeCommonProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
void getSomeSpecificProperty() { printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class T, class Functor>
struct FunctorVisitor : Visitor {
Functor f_;
FunctorVisitor(Functor f) : f_(f) {}
void visit(T& t) { f_(t); } // apply to T objects only
template<class P> void operator()(P const& p) { p->accept(*this); }
};
template<class T, class Functor>
FunctorVisitor<T, Functor> apply_to(Functor f)
{
return FunctorVisitor<T, Functor>(f);
}
int main()
{
typedef boost::intrusive_ptr<BaseObject> BaseObjectPtr;
typedef std::vector<BaseObjectPtr> Objects;
Objects objects;
objects.push_back(BaseObjectPtr(new BaseObject));
objects.push_back(BaseObjectPtr(new Object1));
for_each(
objects.begin()
, objects.end()
, boost::bind(&BaseObject::getSomeCommonProperty, _1)
);
for_each(
objects.begin()
, objects.end()
, apply_to<BaseObject>(boost::bind(&BaseObject::getSomeCommonProperty, _1))
);
for_each(
objects.begin()
, objects.end()
, apply_to<Object1>(boost::bind(&Object1::getSomeSpecificProperty, _1))
);
}
Output:
$ ./test
virtual void BaseObject::getSomeCommonProperty()
virtual void Object1::getSomeCommonProperty()
virtual void BaseObject::getSomeCommonProperty()
void Object1::getSomeSpecificProperty()
I think you should go for option 1 but use a static cast instead. After all the derived collection knows the type of the member variable for sure.
This answer explains it very well.
Id use nested adapter as in below example. You have to specialize it for every class you want to do a fancy update
!The example has memory leak - allocated A, B, Q objects are not deleted!
#include <iostream>
#include <vector>
#include <algorithm>
class Q
{
public:
virtual void Foo()
{
std::cout << "Q::Foo()" << std::endl;
}
};
class A
{
public:
virtual void Foo()
{
std::cout << "A::Foo()" << std::endl;
}
};
class B : public A
{
public:
virtual void Foo()
{
std::cout << "B::Foo()" << std::endl;
}
virtual void BFoo()
{
std::cout << "B::BFoo()" << std::endl;
}
};
template <typename ElementType>
class C
{
public:
template <typename T>
void add(T* ptr){m_Collection.push_back(std::unique_ptr<Adapter>(new ConcreteAdapter<T>(ptr)));}
void updateAll()
{
std::for_each(m_Collection.begin(), m_Collection.end(), [&](std::unique_ptr<Adapter> &adapter)->void{adapter->update();});
}
private:
class Adapter
{
public:
virtual ElementType* get() = 0;
virtual void update(){get()->Foo();}
};
template <typename T>
class ConcreteAdapter : public Adapter
{
public:
ConcreteAdapter(T* ptr) : m_Ptr(ptr){}
virtual T* get(){return m_Ptr;}
protected:
T* m_Ptr;
};
template <>
class ConcreteAdapter<B> : public Adapter
{
public:
ConcreteAdapter(B* ptr) : m_Ptr(ptr){}
virtual B* get(){return m_Ptr;}
virtual void update()
{
get()->Foo();
get()->BFoo();
}
private:
B* m_Ptr;
};
std::vector<std::unique_ptr<Adapter>> m_Collection;
};
int main()
{
C<A> c;
c.add(new A());
c.add(new B());
//c.add(new Q()); //error - correct
c.updateAll();
return 0;
}
Maybe this will do the trick here ?
class CollectionManipulator {
public:
void someCommonTask(BaseCollection& coll) {
for(unsigned int i = 0; i < coll.size(); i++)
someCommonTask(coll.getObj(i));
}
private:
void someCommonTask(BaseObject*); // Use baseObjects
};
class BaseCollection {
friend class CollectionManipulator;
private:
virtual BaseObject* getObj(unsigned int) = 0;
virtual unsigned int size() const = 0;
};
class Collection1 : public BaseCollection {
vector<Object1*> objects;
public:
virtual void addObject() {
Object1* obj = new Object1;
objects.push_back(obj);
baseObjects.push_back(obj);
}
void someSpecificTask(); // Use objects, no need of dynamic_cast<>
private:
BaseObject* getObj(unsigned int value) {
return object[value];
}
unsigned int size() const {
return objects.size();
}
}
If you want abstract your container in Collection1 (like using list instead using vector), to use it in Manipulator, create an abstract iterator...
I think the solution should be a mix of factory method pattern and template method pattern. Take a look at those to refine your design.
Edit: Here is a sample code. GenericProduct is the BaseObject, it provides two methods, one that is general (though it could be overridden), and a specific method which does nothing, it is not a pure virtual so this class can be instantiated. SpecificProduct is a subclass, which implements the specific method in some way.
Now, Factory class is an abstract class that defines an interface for creating specific products by specific factories, it defines a pure virtual method createProduct which creates the product. Two concrete factories are created GenericFactory and SpecificFactory which create specific products.
Finally, the Consumer abstract class (which corresponds to BaseCollection in your code), it defines a pure virtual method for creating a factory createFactory in order to force subclasses to create their own concrete factories (and hence, the correct products). The class also define a method fillArray (prototype pattern) to fill the array with products created by the factory.
#include <iostream>
#include <vector>
using namespace std;
class GenericProduct{
public:
virtual void getSomeCommonProperty()
{
cout<<"Common Property\n";
}
virtual void getSomeSpecificProperty()
{
cout<<"Generic Has Nothing Specific\n";
}
};
class SpecificProduct : public GenericProduct{
public:
virtual void getSomeSpecificProperty()
{
cout<<"Specific Product Has a Specific Property\n";
}
};
class Factory
{
public:
virtual GenericProduct* createProduct() = 0;
};
class GenericFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new GenericProduct();
}
};
class SpecificFactory : public Factory
{
public:
virtual GenericProduct* createProduct()
{
return new SpecificProduct();
}
};
class Consumer
{
protected:
vector<GenericProduct*> gp;
Factory* factory;
protected:
virtual void createFactory() = 0;
public:
void fillArray()
{
createFactory();
for(int i=0; i<10; i++)
{
gp.push_back(factory->createProduct());
}
}
virtual void someCommonTask()
{
cout<<"Performaing a Common Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeCommonProperty();
}
}
virtual void someSpecificTask()
{
cout<<"Performaing a Specific Task ...\n";
for(int i=0; i<10; i++)
{
gp[i]->getSomeSpecificProperty();
}
}
};
class GenericConsumer : public Consumer
{
virtual void createFactory()
{
factory = new GenericFactory();
}
};
class SpecificConsumer : public Consumer
{
virtual void createFactory()
{
factory = new SpecificFactory();
}
};
int main()
{
Consumer* c = new GenericConsumer();
c->fillArray();
c->someCommonTask();
return 0;
}