views:

252

answers:

4

Hi,

Consider this simple code:

class A {
};

class V1: vector<A *>{
  // my nice functions
};

if I have a instance of V1, then any object derived from A can be inserted into the vector, ok here.

Now, lets say I have two simple classes called B and C both derives from A;
if I have a instance of V1, then both pointers of B and C can be inserted into this vector, I guess this is right to afirm?

if so, how can I derive a vector from V1 to make sure only B pointers are inserted?
I was thinking about using templates, but in this case I already know the base of the class and in tempaltes you can use anything, right?

Don't know if I am being clear, my english doesn't help...
Would I have to override push_back and other functions to check if the template argument is derived from A?

Please, don't need to talk about boost or syntaxes I am using etc... I really just want to understand the concept of this... it is not clear in my mind yet. I have some answers to this but I guess they involve too much of casts to check stuff and I came here to know if there is a better answer to it...

Thanks!
Jonathan

ps: Can you guys please answer comments I put? sometimes I ask stuff here and then the best answerers come and don't come back :(. Or should I just ask another question instead of comment questioning?

+1  A: 

As a general rule of thumb, you shouldn't derive from STL containers. Why not use a vector<A*> member inside of class V1?

Marcin
ok, even if so, how can I make sure the template has only B pointers(in the case above)?
Jonathan
`typedef vector<B*> VectorOfBs;` ?
Andy Ross
but I already have a class with functions that uses vector of A members and routines, so vector<B*> would need those functions
Jonathan
+3  A: 

It's not clear from your example if inheritance is needed. You may also not realize it is dangerous, because std::vector does not have a virtual destructor. That means V1's destructor will not be called upon deletion of a pointer to the base class and you may end up leaking memory/resources. See here for more info.

class A {
};

class V1: vector<A *>{
  // my nice functions
};

if I have a instance of V1, then any object derived from A can be inserted into the vector, ok here.

Yes, correct.

Now, lets say I have two simple classes called B and C both derives from A; if I have a instance of V1, then both pointers of B and C can be inserted into this vector, I guess this is right to afirm?

Yes, correct.

if so, how can I derive a vector from V1 to make sure only B pointers are inserted? I was thinking about using templates, but in this case I already know the base of the class and in tempaltes you can use anything, right?

Why not use a

std::vector<B*> m_bVector;

for this case? Here's how it would work:

B* bInstance = new B();
A* aInstance = new A();
m_bVector.push_back(bInstance);
m_bVector.push_back(aInstance); //< compiler error

Maybe you have a good reason for inheriting from vector, but I don't see it right now... If you need added functionality, it may be better to have V1 wrap the std::vector, ie:

class V1
{
private:
   std::vector<A*> m_aVec;
public:
   // use AVec
}
Doug T.
I have several functions that logically can't have different objects inside a same vector, even thought they derive from teh same class. But they must derive from A so I can use A members and functions...
Jonathan
reading your post and thinking about what you wrote... yes, I can wrap teh vector inside the class and if need, use templates for outside
Jonathan
"they must derive from A so I can use A members and functions". I suggest a redesign: write V1 as a template class instead of a plain class. Make it a "container adaptor", like `std::stack`, meaning that it has a vector (or other container) as a member, and has functions of its own that you need. Then you can create a `V1<A*, vector>`, `V1<B*, vector>`, or whatever.
Steve Jessop
<quote>That means V1's destructor</quote> Not totally accurate. The destructor is only not called if it is destroyed via a pointer to the base class.
Martin York
thanks @Martin, updated.
Doug T.
+1  A: 

If you want to store B-pointers in your vector, the best solution is to derive from

std::vector<B*>

Or if you want to have possibility to use your class also with A-pointers, make a template

template<typename T>
class MyVec : public std::vector<T> {
};

MyVec<A*> va; // stores A* and B*
MyVec<B*> vb; // stores B* only
qba
yeah, but in template case, how can I make sure that T is derived from A? in C# it would be the "where" keyword. Like: class S: List<T> where T: A {}. My question is if I have to use casts to check that
Jonathan
@Jonhathan: If MyVec's functions use the interface of A, then instantiating a MyVec on a type that does not have the required interface will simply not compile.
Éric Malenfant
could you give me an example? couldn't understand it right. Or the name of this that I go search in google
Jonathan
Hum, not sure I'll be able to write that in a comment... Let's try: class A {public: void bar()=0}; template<class T> class V1{public: void foo(T*){T->bar();}}; class B : public A{}; class C{public: void baz()}; V1<B> vb; //OK, compiles fine vb.foo();V1<C> vc;vc.foo(); //Oups! Error: "bar()" is not a member of C
Éric Malenfant
If class you give as template parameter doesn't comply template conditions compilation will fail. If it does why do not allow to make vector of this class. This is concept of templates - if something have appropriate methods let it work with template. Simply do not create MyVec<char> if it cannot work.
qba
understod... in this case it wouln't check inheritance, but members... interesting. Thanks!
Jonathan
Given my inability to properly write code in a comment, I wrote it properly on codepad: http://codepad.org/n6hvP02f
Éric Malenfant
A: 

if so, how can I derive a vector from V1 to make sure only B pointers are inserted?

Setting aside that you shouldn't inherit from the STL container (for a number of reasons that may not be obvious), the answer is that you don't. Not really, anyway.

You can make a run-time assertion that only B* can be inserted:

if(!dynamic_cast<B*>(item))
    return false;

But this relies on C++'s RTTI support, which is typically very slow. You could instead use some kind of "roll-your-own" RTTI interface (i.e., a function that returns an enum identifying the class), or perhaps Boost's static assert testing the typeof the object.

My preference would be this:

template<typename T>
class V1 {
private:
    std::vector<T*> _vec;
// ...
};

And then instantiate with a type for T that makes sense for your use case.

But if you have a case that relies on sometimes there being all B*s and sometimes all A*s, then I would submit that your design stinks and should be rethought.

greyfade
lol =p . Its not my case hehe, the vector will never have mixed types, but I will have functions using the base of that instances, like loading xml data etc
Jonathan
Then I submit that your design is wrong and that you are using inheritance inappropriately.
greyfade