vector and shared_ptr to base class

D

Dimitry

I am trying to make the following:

struct Base
{
char param[FIXED_NUMBER];
};

class Derived1 : public Base
{
public:
void setParam(char c)
{
param[1] = c;
}
};

class Derived2 : public Base
{
public:
void setParam(char c)
{
param[2] = c;
}
};

shared_ptr<Derived1> d1(new Derived1);
d1->setParam(0x10);

shared_ptr<Derived2> d2(new Derived2);
d2->setParam(0x20);

//What the best way of doing this?
vector<shared_ptr<Base> > v;
v.push_back(d1);
v.push_back(d2);
....
//Somewhere for example
shared_ptr<Base> b = *iter;
reverse_bits(b.param);

Obviously v.push_back(d1) is not going to work because there will be
"no matching function for call". But what the best way of doing this?
 
V

Victor Bazarov

Dimitry said:
I am trying to make the following:

struct Base
{
char param[FIXED_NUMBER];
};

class Derived1 : public Base
{
public:
void setParam(char c)
{
param[1] = c;
}
};

class Derived2 : public Base
{
public:
void setParam(char c)
{
param[2] = c;
}
};

shared_ptr<Derived1> d1(new Derived1);
d1->setParam(0x10);

shared_ptr<Derived2> d2(new Derived2);
d2->setParam(0x20);

//What the best way of doing this?
vector<shared_ptr<Base> > v;
v.push_back(d1);
v.push_back(d2);
...
//Somewhere for example
shared_ptr<Base> b = *iter;
reverse_bits(b.param);

Obviously v.push_back(d1) is not going to work because there will be
"no matching function for call". But what the best way of doing this?

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);
...

V
 
D

Dimitry

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(){..}
};
 
S

Salt_Peter

[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.
 
D

Dimitry

Thanks guys,

What I actually meant is setParamN shall be public.
Let's put this different way:

void makeMagicQuick(string s)
{
//make magic with Base::param
}

void makeMagicSlow(int i)
{
//make magic with Base::param
}

void makeMagicAsUsual(vector<..>& v)
{
//make magic with Base::param
}
....
And number of such makeMagicN is a lot and each does own trick with
Base::param.
This is why we need derived classes in a first place to make the
Base::param more friendly.
Each makeMagic is a meaningful name and makeMagicQuick and
makeMagicSlow have nothing in common apart from that they use
Base::param.
 
S

Salt_Peter

Dimitry said:
Thanks guys,

What I actually meant is setParamN shall be public.

Whether setParamN is public, protected, private or even non-existant is
irrelevent. setParamN is not part of the Base's interface. And your
goal is to store Base-type elements. So you could implement RTTI and do
it the ugly way or you can simply use the concept already explained to
you.
Let's put this different way:

void makeMagicQuick(string s)
{
//make magic with Base::param
}

That makes no sense. makeMagicQuick is not a type's member function.
Functions do not have Bases and neither are they objects.
void makeMagicSlow(int i)
{
//make magic with Base::param
}

void makeMagicAsUsual(vector<..>& v)
{
//make magic with Base::param
}
...
And number of such makeMagicN is a lot and each does own trick with
Base::param.
This is why we need derived classes in a first place to make the
Base::param more friendly.

Base::param serves no one. The derived entities are being classified
using the Base's type. Each derived entity enjoys the priveledge of
having a Base counterpart. And it is a priveledge because without it,
you can't store the derived instances in one Base container.
Each makeMagic is a meaningful name and makeMagicQuick and
makeMagicSlow have nothing in common apart from that they use
Base::param.

What? makeMagic is not an object and therefore can't have a Base. You
are making no sense at all.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,969
Messages
2,570,161
Members
46,710
Latest member
bernietqt

Latest Threads

Top