I want a vector of derived class pointers as base class pointers
There is a copy constructor for a std::vector
but it requires you to copy the exact same type of vector. Fortunately, there is another constructor which takes a pair of iterators and adds all the elements in the range, so you can do this:
vector<Animal*> animals(dogs.begin(),dogs.end());
This creates a new vector of Animal
pointers by iterating through each Dog
pointer. Each Dog
pointer is converted to an Animal
pointer as it goes.
Here is a more complete example (using C++11):
#include <vector>
struct Animal { };
struct Dog : Animal { };
struct Cat : Animal { };
struct Bird : Animal { };
int main(int,char**)
{
Dog dog1, dog2;
Cat cat1, cat2;
Bird bird1, bird2;
std::vector<Dog *> dogs = {&dog1,&dog2};
std::vector<Cat *> cats = {&cat1,&cat2};
std::vector<Bird *> birds = {&bird1,&bird2};
std::vector<std::vector<Animal *>> all_animals = {
{dogs.begin(),dogs.end()},
{cats.begin(),cats.end()},
{birds.begin(),birds.end()}
};
}
Vector of pointers to base class containing base and derived class objects - accessing derived-class specific variables
Yes it is possible. You only need to cast the pointer. The simplest syntax is:
((Derived*)e)->DerviedVariable
which is equivalent (modulo casting away constness, if any) to C++ish
static_cast<Derived*>(e)->DerviedVariable
The word “static” here reminds that there is no runtime checking: the compiler trusts you that e
indeed points to an instance of Derived
. If it doesn’t, undefined behavior occurs. The safer alternative is dynamic_cast
:
Derived *ee = dynamic_cast<Derived*>(e);
if (ee)
x = ee->DerviedVariable;
It returns NULL if the object is not an instance of Derived
. (Note that references can be casted as well, but as there is no NULL reference, dynamic_cast
will throw instead if cast is not possible)
Nevertheless, using such casts is often considered a bad practice, for a reason. Virtual functions are preferable, mostly because using them don’t require you to even know the actual object type at the call point.
Making a vector of base class pointers and pass Derived class objects to it (Polymorphism)
I see that you have an array in Menu, let's say:
Shape* myshapes[10];
The shapes can be Rectangles, Triangles, Circles etc.
What you want is to be able to use the Menu's printDetails() method like this:
void printDetails()
{
for(int i = 0; i < size; i++)
{
cout << "Index " << i << " has " << myshapes[i]->getShapeName() << endl;
}
}
The getShapeName() will return a string, e.g. "Rectangle" if it is Rectangle.
You will be able to do this with the help of pure virtual function. The pure virtual function must be in the abstract class Shape, which has:
virtual string getShapeName() = 0; //pure virtual
It means that we are expecting a definition for this function in the derived class. This way you will be able to use getShapeName() method using the Shape pointers in the shapes array, which will tell you whether the shape is Rectangle, Triangle, or Circle etc.
class Shape
{
public:
virtual string getShapeName() = 0;
};
class Circle : public Shape
{
private:
int radius;
public:
Circle(int r) { radius = r; cout << "Circle created!\n"; }
string getShapeName() { return "Circle"; }
};
class Arrow : public Shape
{
private:
int length;
public:
Arrow(int l) { length = l; cout << "Arrow created!\n"; }
string getShapeName() { return "Arrow"; }
};
class Polygon : public Shape
{
public:
virtual string getShapeName() = 0;
};
class Triangle : public Polygon
{
private:
int x, y, z;
public:
Triangle(int a, int b, int c) { x = a; y = b; z = c; cout << "Triangle created!\n"; }
string getShapeName() { return "Triangle"; }
};
class Rectangle : public Polygon
{
private:
int length;
int width;
public:
Rectangle(int l, int w){ length = l; width = w; cout << "Rectangle created!\n"; }
string getShapeName() { return "Rectangle"; }
};
To implement the addShape() method you can do this:
void addShape(Shape &shape)
{
myshapes[count] = &shape;
count++;
}
Also, keep in mind to pass the Shape by reference or by using pointer, in the addShape() method.
I hope this helps... Best of luck :-)
Best way to store std::vector of derived class in a host parent class
tldr: Use a variant or type erasure, depending on context.
What you are asking for in C++ would be described roughly as a value type or a type with value semantics. You want a type that is copyable, and copying just "does the right thing" (copies do not share ownership). But at the same time you want polymorphism. You want to hold a variety of types that satisfy the same interface. So... a polymorphic value type.
Value types are easier to work with, so they will make a more pleasant interface. But, they may actually perform worse, and they are more complex to implement. Therefore, as with everything, discretion and judgment come into play. But we can still talk about the "best practice" for implementing them.
Let's add an interface method so we can illustrate some of the relative merits below:
struct Base {
virtual ~Base() = default;
virtual auto name() const -> std::string = 0;
};
struct Derivative1: Base {
auto name() const -> std::string override {
return "Derivative1";
}
};
struct Derivative2: Base {
auto name() const -> std::string override {
return "Derivative2";
}
};
There are two common approaches: variants and type erasure. These are the best options we have in C++.
Variants
As you imply, variants are the best option when the set of types is finite and closed. Other developers are not expected to add to the set with their own types.
using BaseLike = std::variant<Derivative1, Derivative2>;
struct Host {
std::vector<BaseLike> derivativeList;
};
There's a downside to using the variant directly: BaseLike
doesn't act like a Base
. You can copy it, but it doesn't implement the interface. Any use of it requires visitation.
So you would wrap it with a small wrapper:
class BaseLike: public Base {
public:
BaseLike(Derivative1&& d1) : data(std::move(d1)) {}
BaseLike(Derivative2&& d2) : data(std::move(d2)) {}
auto name() const -> std::string override {
return std::visit([](auto&& d) { return d.name(); }, data);
}
private:
std::variant<Derivative1, Derivative2> data;
};
struct Host {
std::vector<BaseLike> derivativeList;
};
Now you have a list in which you can put both Derivative1
and Derivative2
and treat a reference to an element as you would any Base&
.
What's interesting now is that Base
is not providing much value. By virtue of the abstract method, you know that all derived classes correctly implement it. However, in this scenario, we know all the derived classes, and if they fail to implement the method, the visitation will fail to compile. So, Base
is actually not providing any value.
struct Derivative1 {
auto name() const -> std::string {
return "Derivative1";
}
};
struct Derivative2 {
auto name() const -> std::string {
return "Derivative2";
}
};
If we need to talk about the interface we can do so by defining a concept:
template <typename T>
concept base_like = std::copyable<T> && requires(const T& t) {
{ t.name() } -> std::same_as<std::string>;
};
static_assert(base_like<Derivative1>);
static_assert(base_like<Derivative2>);
static_assert(base_like<BaseLike>);
In the end, this option looks like: https://godbolt.org/z/7YW9fPv6Y
Type Erasure
Suppose instead we have an open set of types.
The classical and simplest approach is to traffic in pointers or references to a common base class. If you also want ownership, put it in a unique_ptr
. (shared_ptr
is not a good fit.) Then, you have to implement copy operations, so put the unique_ptr
inside a wrapper type and define copy operations. The classical approach is to define a method as part of the base class interface clone()
which every derived class overrides to copy itself. The unique_ptr
wrapper can call that method when it needs to copy.
That's a valid approach, although it has some tradeoffs. Requiring a base class is intrusive, and may be painful if you simultaneously want to satisfy multiple interfaces. std::vector<T>
and std::set<T>
do not share a common base class but both are iterable. Additionally, the clone()
method is pure boilerplate.
Type erasure takes this one step more and removes the need for a common base class.
In this approach, you still define a base class, but for you, not your user:
struct Base {
virtual ~Base() = default;
virtual auto clone() const -> std::unique_ptr<Base> = 0;
virtual auto name() const -> std::string = 0;
};
And you define an implementation that acts as a type-specific delegator. Again, this is for you, not your user:
template <typename T>
struct Impl: Base {
T t;
Impl(T &&t) : t(std::move(t)) {}
auto clone() const -> std::unique_ptr<Base> override {
return std::make_unique<Impl>(*this);
}
auto name() const -> std::string override {
return t.name();
}
};
And then you can define the type-erased type that the user interacts with:
class BaseLike
{
public:
template <typename B>
BaseLike(B &&b)
requires((!std::is_same_v<std::decay_t<B>, BaseLike>) &&
base_like<std::decay_t<B>>)
: base(std::make_unique<detail::Impl<std::decay_t<B>>>(std::move(b))) {}
BaseLike(const BaseLike& other) : base(other.base->clone()) {}
BaseLike& operator=(const BaseLike& other) {
if (this != &other) {
base = other.base->clone();
}
return *this;
}
BaseLike(BaseLike&&) = default;
BaseLike& operator=(BaseLike&&) = default;
auto name() const -> std::string {
return base->name();
}
private:
std::unique_ptr<Base> base;
};
In the end, this option looks like: https://godbolt.org/z/P3zT9nb5o
Pass vector of derived class pointers to thread
To make your example work, there are a few mistakes that need to be corrected.
- As
Consumer::doStuff
is a non-static member function, you need an instance ofConsumer
to run it on. - Because of above,
Consumer
needs a defined constructor - The signature of
doStuff
needs to take a (reference to a) vector ofBase
pointers, notBase
objects - Thread
t3
needs said instance ofConsumer
as its first forwarded parameter (to provide thethis
parameter.
Final working code:
#include<vector>
#include<thread>
#include<iostream>
using namespace std;
class Base
{
public:
Base() {};
void dosomething() {cout<<i<<endl;}
int i;
};
class Derived1 : public Base
{
public:
Derived1() {i = 5;}
};
class Derived2 : public Base
{
public:
Derived2() {i = 10;}
};
class Consumer
{
public:
Consumer() {}
void dostuff( vector<Base*> &pointervec) {cout<<pointervec.at(0)->i<<endl;}
};
int main( int argc, char ** argv )
{
Derived1 derived1;
Derived2 derived2;
Consumer c;
vector<Base*>pointervec;
pointervec.push_back(&derived1);
pointervec.push_back(&derived2);
std::thread t1(&Derived1::dosomething, &derived1);
std::thread t2(&Derived2::dosomething, &derived2);
std::thread t3(&Consumer::dostuff, &c, ref(pointervec));
t1.join();
t2.join();
t3.join();
}
Cast vector with base class pointers to back to subclass
I want to cast a vector of base class pointers to a vector of subclass pointers.
You can't.
Let me try to explain why that would be a problem if the compiler let you do that. Let's say you have another class derived from txt_base
.
#include <vector>
class txt_base {
int a;
};
class txt_specific : public txt_base {
int b;
void do_stuff(){};
};
class txt_utf8 : public txt_base {
// ...
// Member data
// ...
void do_stuff(){};
};
int main() {
std::vector<txt_base *> x {new txt_specific(), new text_utf8()};
// Let's say te compiler allowed this
std::vector<txt_specific *> y = (std::vector<txt_specific *>) x;
txt_specific* ptr = y[1];
// Now you have ptr of type txt_specific that really points to a txt_utf8.
// Dereferencing ptr and using it member variables and member functions will
// lead to undefined behavior.
}
Casting a single object with
txt_specific *o = (txt_specific *) x.front();
works but I cannot figure out how to cast the whole vector at once.
I hope I have explained why you should not attempt to do that. The choices for you are:
Get a pointer to the base class and then perform a
dynamic_cast
. Please note that you'll need to change the base class to have at least onevirtual
member function before usingdynamic_cast
. Making the destructorvirtual
is the easiest choice. It is also appropriate when you want to delete derived class objects using a base class pointer.class txt_base {
public:
virtual ~txt_base() {}
private:
int a;
};and
txt_base* ptr = x.front();
txt_specific* o = dynamic_cast<txt_specific *>(ptr);
if ( o != nullptr )
{
// Use o
}Keep a vector of derived class pointers. Then you don't have to worry about casting.
Related Topics
Differencebetween Set and Unordered_Set in C++
Are Virtual Destructors Inherited
Do Rvalue References Allow Dangling References
How to Change String into Qstring
Why Is Std::Min Failing When Windows.H Is Included
C++ Lambdas How to Capture Variadic Parameter Pack from the Upper Scope
How to Determine the Size of an Object in C++
Why Is "!=" Used with Iterators Instead of "<"
How to Get the Real and Total Length of Char * (Char Array)
Conversion Function for Error Checking Considered Good
How to Connect MySQL Database Using C++
C++ Data Alignment /Member Order & Inheritance
Sse, Intrinsics, and Alignment
Openmp Set_Num_Threads() Is Not Working
Find All Substring's Occurrences and Locations
Why Do We Actually Need Private or Protected Inheritance in C++