[rearranged]
Victor said:
Not going to work if your 'Base' is non-polymorphic class. If you do
struct Base {
char param[WHATEVER];
virtual ~Base() {}
virtual void setParam(char) = 0;
};
*Then* you could try
vector<shared_ptr<Base> > v;
v.push_back(new Derived1);
v.push_base(new Derived2);
v[0].setParam(0x10);
v[1].setParam(0x20);
hmm, v[0]->setParam(...);
If for example Derived1 has setParam1 function, Derived2 - setParam2
etc. and I have a lot of these derived and each derived has own
customized 'set'-functions that Base class has no idea of.
How can I make it properly?
For example:
struct D1 : Base
{
void setParam1(){..}
void setParam2(){..}
void setParam3(){..}
};
struct D2 : Base
{
void setParam4(){..}
};
struct D3 : Base
{
void setParam5(){..}
void setParam6(){..}
};
Thats exactly what Victor is trying to explain.
The base class doesn't need to know anything. What D2 does is also
inconsequential to D3, etc. Even the container that will store a
mixture of these doesn't care about the derived class's specifics or
internals.
The goal here is to provide a base class where the creator of the class
(you) can impose a rule that says: "You must provide the implementation
for this pure virtual member function if you choose to derive from this
base class - my system requires it". This way the derivatives can
safely use a polymorphicly distributed member function to fullfill its
particular needs and the container will always have that virtual member
function available regardless of the actual type of the element
involved. Sounds complicated but its a simple concept.
#include <iostream>
#include <vector>
struct Base // pure abstract
{
virtual ~Base() { std::cout << "~Base()\n"; }
virtual void setParam() = 0; // pure virtual member function
};
class D1 : public Base
{
void setParam1() { std::cout << "setParam1()\n"; } // private
void setParam2() { std::cout << "setParam2()\n"; }
public:
~D1() { std::cout << "~D1()\n"; }
void setParam() // required by Base
{
std::cout << "setParam()\n";
setParam1();
setParam2();
}
};
int main()
{
// Base base; // illegal - its abstract
vector< shared_ptr< Base > > v;
v.push_back( new D1 ); // etc...
v[0]->setParam(); // does the D1 boogie, whatever that might be
}
/*
setParam() // system-wide
setParam1() // internal
setParam2() // internal
~D1()
~Base() // correctly invoked by derived d~tor
*/
Note how the container doesn't care about what D1 actually does. Thats
the element-type's responsability alone. Why is that important? Cause
then the system is easy to expand and hard to break. You, the creator,
have imposed a small rule in order to use the code. The client
programmer can expand the system knowing that the its safely
extendeable. And the client can do this with the assurance that he can
add new derivatives 2, 5 or 10 years from now whithout having to
change/modify a single line of the original code.
As a side note, in this case, i'ld probably be using the ctor's init
lists to set members instead. 'Course, i don't know what the
requirements are...
class D2
{
const char a;
const char b;
public:
D2() : a('a'), b('b') { }
D2(char a_, char b_) : a(a_), b(b_) { }
D2() : a( setParam1() ), b( setParam2() ) {} // no problem
const char setParam1() const { return 'a'; }
const char setParam2() const { return 'b'; }
};
but thats an entirely different issue.