nnrales
nnrales

Reputation: 1519

Making a pointer to std::vector of base class pointers point to std::vector of derived class pointers

Apologize for the verbose title. I do not know how to express this succinctly.

class A 
{
      bool a1; 
      unsigned int a2 ; 
      virtual bool aFn1(unsigned int t_) = 0 ; 
      virtual void aFn2(unsigned int t_, bool val_) = 0 ;  
      A() 
      {
           a1 = false ; a2 = 0 ; 
      };
}

Next:

#include <bitset> 
#define MAX_SIZE 500 

class B : public class A 
{
  private: 
     std::bitset<MAX_SIZE> _bmem; 
  public:
     B() : A() {}; 
     using A::aFn1 ;            
     virtual bool aFn1(unsigned int t_) 
        {
           return _bemem[t_] 
        } 
      using A::aFn2;
     virtual void aFn2(unsigned int t_, bool val_)
     {
        _bemem[t_] = val_ ; 

     }
}

Next:

#include "A.h"
#include "B.h"

std::vector<A*> * vecA; 
vecA = new std::vector<B*> ; 

But this last step does not work. clang complete tells me

assigning to std::vector<A*> * from incompatible type std::vector<B*>

But since B derives from A, this should be possible right? I have seen examples where people use

B bObj;
A *aObj = &bObj ;

So could you please tell me what mistake I am making?

The reason I go through all this, is because I have class C and class D, exactly like class B, where the only difference is that #define MAX_SIZE is different.

I do this because, I need a bitset of different sizes, to be used in different phases of the program. And bitset requires the number of elements it needs to store at compile time.

Upvotes: 0

Views: 413

Answers (4)

Toby Speight
Toby Speight

Reputation: 30831

This boils down to

std::vector<Base*> *v = new std::vector<Derived*>;

But std::vector<Base*> and std::vector<Derived*> aren't compatible types, for the same reason that you can't use an array of Derived* as an array of Base*.

For example, in the above, what should happen if you write v->push_back(new Base())? You can't have a Base* in your vector of Derived*.

For a good explanation of the issues involved in treating a Derived* as a Base*, see also the reasoning behind this answer to "Converting std::function<void(Derived*)> to std::function<void(Base*)>", which is the same issue in a different guise.

Upvotes: 0

Yakk - Adam Nevraumont
Yakk - Adam Nevraumont

Reputation: 275395

You are using far too many interfaces and pointers.

class A  {
  bool a1 = false; 
  unsigned int a2 = 0; 
  std::vector<bool> values;
  bool aFn1(unsigned int t_) const { return values[t_]; }
  void aFn2(unsigned int t_, bool val_) { values[t_] = val_; }
  void set_size(size_t i){values.resize(i);}
  A() = default;
  static A of_size(size_t i){ A r; r.set_size(i); return r; }
};

then use a std::vector<A>.

If you 100 elements of size 500, do std::vector<A> v( 100, A::of_size(500) );

This code will do fewer allocations, use less memory, and have less indirection than your code. Using new is "code smell", often a sign you have made a mistake, unless you really need objects of extremely complex lifespan.

A std::vector<bool> values will be nearly as compact as a std::bitset<500>, and the difference is made up by the other pointers I eliminated.

Upvotes: 3

eerorika
eerorika

Reputation: 238351

clang complete tells me assigning to std::vector<A*> * from incompatible type...

Clang tells you the truth.

But since B derives from A, this should be possible right?

Not right.

I have seen examples where people use

B bObj;
A *aObj = &bObj ;

Those examples are correct. They work because A is a parent of B. A pointer of a child class can be converted to a pointer to a parent class.

So could you please tell me what mistake I am making?

You're trying to assign a pointer to std::vector<B*> into a pointer to std::vector<A*>. std::vector<A*> is not a parent of std::vector<B*>. In terms of inheritance they are entirely unrelated classes. Pointer to a type cannot be converted to a pointer to an unrelated type.

Upvotes: 2

TartanLlama
TartanLlama

Reputation: 65620

You cannot make a std::vector<A*>* point to a std::vector<B*>*, those are disparate types.

What you can do is push B* into a std::vector<A*>:

std::vector<A*> vec;
B b;
vec.push_back(&b);

Of course you need to be careful about the lifetime of the pointers. You might want to use std::unique_ptr if the vector should manage the lifetime itself.

Also note that A needs a virtual destructor, otherwise it is undefined behaviour to delete a B* through an A*.

Upvotes: 2

Related Questions