cal...">

C ++ vector with inheritance

Link Code:

#include <vector> #include <iostream> class Func { public: virtual void call() { std::cout<< "Func -> call()" << std::endl; } }; class Foo : public Func { public: void call() { std::cout<< "Foo -> call()" << std::endl; } }; class Bar : public Func { public: void call() { std::cout<< "Bar -> call()" << std::endl; } }; int main(int argc, char** argv) { std::vector<Func> functors; functors.push_back( Func() ); functors.push_back( Foo() ); functors.push_back( Bar() ); std::vector<Func>::iterator iter; for (iter = functors.begin(); iter != functors.end(); ++iter) (*iter).call(); } 

When I run this code on my computer, the following output is generated:

 $ ./test Func -> call() Func -> call() Func -> call() 

Will there be any way to ensure that the correct virtual function is called in this case? I am new to C ++, but I think here:

 (*iter).call(); 

Applies to a Func object. Is it correct?

+6
source share
6 answers

You must use shared_ptr or unique_ptr to store polymorphic type elements.

Once your code is written, instances of Foo and Bar are copied (copied) to an instance of type Func to be inserted into the vector. (The reason is that the vector saves its elements immediately by a fixed size value for performance, however polymorphic subclasses have an arbitrarily large size unknown at compile time, so it can only store the base class.)

It is better:

 int main(int argc, char** argv) { vector<shared_ptr<Func>> functors; functors.push_back( make_shared<Func>() ); functors.push_back( make_shared<Foo>() ); functors.push_back( make_shared<Bar>() ); for (auto functor : functors) functor->call(); } 

The reference counting pointer above is used to implicitly exchange heterogeneous Func subclasses in a vector. (This indirect use allows you to arbitrarily fine-tune Func subclasses by address numbering.)

In addition, you might want to take a look at std :: function and std :: bind, rather than the rotation of your own functor type.

Another thing you need to pay attention to are the excellent call forwarding and varadic patterns.

update : for the old compiler:

 int main(int argc, char** argv) { vector<std::tr1::shared_ptr<Func> > functors; functors.push_back( std::tr1::make_shared<Func>() ); functors.push_back( std::tr1::make_shared<Foo>() ); functors.push_back( std::tr1::make_shared<Bar>() ); for (size_t i = 0; i < functors.size(); ++i) functors[i]->call(); } 
+6
source

the vector only stores the Func type by value, which means that all of your Foo and Bar timestamps are sliced ​​and added to the base Func type

you need to change to something like std::vector< Func* > and dynamically allocate instances of derived classes so that polymorphic dispatch works

If you are completely sure that after this function you will not pass this vector to other functions, you can select instances on the stack as optimization:

 std::vector< Func* > v; Bar b; Foo f; v.push_back( &b); v.push_back( &f); 
+2
source

your std :: vector stores Func objects - this means that when called

 functors.push_back( Foo() ); functors.push_back( Bar() ); 

you create Foo and Bar objects, then "cut" these objects as they are copied to Func objects.

If you want to use Foo and Bar polymorphically, then a more typical template would be to save a vector of some type of pointer (preferably not "raw" pointers), for example

std::vector< std::unique_ptr<Func> >

std::vector< std::shared_ptr<Func> >

Or, if you really need to ... (But only if you are using an old compiler that does not have shared_ptr or unique_ptr)

std::vector< Func* >

+1
source

In C ++, polymorphism only works with pointers and links, while a vector stores instances of objects directly. When you call push_back , the Func copy constructor is called, which builds the Func object that is stored inside the vector.

This is called object slicing, you can learn more about it with a quick search on StackOverflow.

The solution is to store pointers (or, even better, smart pointers) on your objects, which should be allocated elsewhere (probably on the heap).

+1
source

In general, instances of subclasses may be larger than instances of their superclass, so you should not expect subclasses to fit into your vector slot.

And push_back will probably call the internal copy constructor (of the Func class, since you have a vector<Func> ), so the internal vector slots are really Func not for some other classes.

+1
source

Your problem is that you have a Func vector, but the methods are called polymorphically only through links or pointers.

0
source

Source: https://habr.com/ru/post/913211/


All Articles