2

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?

Ben S
  • 68,394
  • 30
  • 171
  • 212
Jonathan
  • 4,724
  • 7
  • 45
  • 65
  • To be clear, you B derives from A, but you don't want to be able to store pointers to B objects in V1, only pointers to A objects? – Marcin Nov 03 '09 at 18:33
  • sorry... I have a abstract class named A, then I will have several classes that derive from A, like B and C. Then there will be a vector of each(or most) derived of A. Like vector, vector, but I would like to create a class that already has lot of functions that uses members and routines of class A and wouldn't like to have to rewrite those things for vectors of B and C... am I still not clear? Sorry again =[ – Jonathan Nov 03 '09 at 18:36

4 Answers4

3

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.
  • 64,223
  • 27
  • 138
  • 202
  • 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 Nov 03 '09 at 18:29
  • 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 Nov 03 '09 at 19:01
  • "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`, `V1`, or whatever. – Steve Jessop Nov 03 '09 at 19:33
  • That means V1's destructor Not totally accurate. The destructor is only not called if it is destroyed via a pointer to the base class. – Martin York Nov 03 '09 at 20:01
2

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
  • 12,245
  • 9
  • 42
  • 49
1

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
  • 1,291
  • 3
  • 15
  • 22
  • 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 where T: A {}. My question is if I have to use casts to check that – Jonathan Nov 03 '09 at 18:48
  • @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 Nov 03 '09 at 18:51
  • could you give me an example? couldn't understand it right. Or the name of this that I go search in google – Jonathan Nov 03 '09 at 18:53
  • 1
    Hum, not sure I'll be able to write that in a comment... Let's try: class A {public: void bar()=0}; template class V1{public: void foo(T*){T->bar();}}; class B : public A{}; class C{public: void baz()}; V1 vb; //OK, compiles fine vb.foo(); V1 vc; vc.foo(); //Oups! Error: "bar()" is not a member of C – Éric Malenfant Nov 03 '09 at 19:03
  • 1
    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 if it cannot work. – qba Nov 03 '09 at 19:09
  • understod... in this case it wouln't check inheritance, but members... interesting. Thanks! – Jonathan Nov 03 '09 at 19:09
  • Given my inability to properly write code in a comment, I wrote it properly on codepad: http://codepad.org/n6hvP02f – Éric Malenfant Nov 03 '09 at 19:10
0

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.

Community
  • 1
  • 1
greyfade
  • 24,948
  • 7
  • 64
  • 80
  • 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 Nov 03 '09 at 21:42
  • Then I submit that your design is wrong and that you are using inheritance inappropriately. – greyfade Nov 12 '09 at 21:52