I'm currently writing a complicated class and in it I basically need to copy a list of derived classes. The simplified version is, as follows:
I have a base class from which I derive several other classes:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual Base& operator=(const Base& rhs)
{
cout << "Base=" << endl;
return *this;
}
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
A& operator=(const A& rhs)
{
cout << "A=" << endl;
return *this;
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
B& operator=(const B& rhs)
{
cout << "B=" << endl;
return *this;
}
};
Then I create a list of objects, which I save in the in a pointer list of the Base class:
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
These objects I then want to copy in a second list with the same classes (same order), but which might have different values.
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
However c++ is not able to do that. Because the list has the type Base*, dereferencing creates an object of type Base. Therefore the assignment operator= of the Base class is called instead of the correct one from the derived class. How can I fix this?
Or how can I tell c++ to use the right operator? Maybe by some isinstanceof-function?
For a full sample see:
int main()
{
vector<Base*> listA;
new Base(&listA);
new A(&listA);
new B(&listA);
vector<Base*> listB;
new Base(&listB);
new A(&listB);
new B(&listB);
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]).test();
}
for (int i = 0; i < (int)listA.size(); i++)
{
(*listA[i]) = (*listB[i]);
}
}
Which outputs:
Base
A
B
Base=
Base=
Base=
There are a few misunderstandings here. First and foremost, what does it mean to assign an instance of a derived class to an instance of a base class? Let's take a simple hierarchy:
struct A { int x; };
struct B : A { int y; };
A a;
B b;
a = b; // what should this do?
b = a; // what about this?
With normal C++, the first one does object slicing, and the second one is ill-formed. But even the first one, well well-formed, is typically not what you want to do anyway. Are you sure you want to be slicing?
The second is that while you made your assignment operator virtual:
virtual Base& operator=(const Base& rhs)
None of the derived classes actually override it. A's assignment operator takes an A const& and B's takes a B const&. If you marked the two with override, your compiler would point this out to you. If you fix those two to take a Base const& argument, then you would get what you want printed - but it's probably still not what you actually want to have happen.
In order to actually make polymorphic copies, a typical solution is to provide a virtual clone method:
virtual Base* clone() const = 0;
That your derived classes implement:
struct A : Base {
A* clone() const override { return new A(*this); }
};
And then use clone() instead of assignment. There will be no slicing here.
Insert the usual caveats about memory management and raw pointers here.
Okay. I found a solution for my problem. I implemented a copy function which takes the Base class as the argument. Inside this copy function I can copy the variables using the pointa. The classe now are as follows:
class Base
{
public:
virtual void test(void)
{
cout << "Base" << endl;
}
Base(vector<Base*> *pointer)
{
pointer->push_back(this);
}
virtual void clone(Base* pointer) = 0;
};
class A : public Base
{
public:
void test(void)
{
cout << "A" << endl;
}
A(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
A* pointa = (A*)pointer;
cout << "clone A" << endl;
//Clone Variables here
}
};
class B : public Base
{
public:
void test(void)
{
cout << "B" << endl;
}
B(vector<Base*> *pointer) : Base(pointer) {}
void clone(Base* pointer) override
{
B* pointa = (B*)pointer;
cout << "clone B" << endl;
//Clone Variables here
}
};
This means I can now copy the objects in the following way:
for (int i = 0; i < (int)listA.size(); i++)
{
listA[i]->clone(listB[i]);
}
However this solution is not in any way typesafe, a requirement I want to meet. I looked into my idea, and decided to do things manually without the list, which means lot's of duplicated code, but brings peace of mind.
Related
I have the following code:
class A {
public:
A() { cout << "A()" << endl; }
void f() { cout << "A" << endl; }
};
class B : public A {
public:
B() { cout << "B()" << endl; }
void f() { cout << "B" << endl; }
void ff() { cout << "ff()" << endl; }
};
int main()
{
A a = B();
B b;
a = b;
}
How calling A a = B(); will be different from A a = A();? Why is the conversion from derived class to base class possible?
When you do A a = B();, copy constructor of class A should be invoked after default constructor of class B has been invoked (Note: Compiler may remove unnecessary copy using copy elison).
A(const A& other)
{
}
Since, object of class B can be passed to copy constructor of class A, it will be allowed but you may experience object-slicing.
If you are curious to know "how is it possible to pass a derived class object to a method accepting a reference to the base class", read the following:
Is it possible to pass derived classes by reference to a function taking base class as a parameter
In the following code, the function foo is copy constructing a Base object c from a Derived object d. My question is: are we getting an exact copy? Because I'm not getting the polymorphic behavior I'm expecting
#include<iostream>
class Base
{
public:
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = new Base(*d);
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Base
}
There is no virtual constructor nor copy constructor.
However, it is possible to define a function that behaves like one.
In my case, it is the virtual member function copy() which I added to OP's sample:
#include <iostream>
class Base
{
public:
virtual Base* copy() const { return new Base(*this); }
virtual void sayHello()
{
std::cout << "Hello Base" << std::endl ;
}
};
class Derived: public Base
{
public:
virtual Base* copy() const override { return new Derived(*this); }
void sayHello() override
{
std::cout << "Hello Derived" << std::endl ;
}
};
void foo(Base* d)
{
Base* c = d->copy();
c->sayHello() ;
}
int main()
{
Derived d;
foo(&d) ; //outputs Hello Derived
return 0;
}
Output:
Hello Derived
Live Demo on coliru
The drawback is that every derived class of Base has to provide it to make it function properly. (I've no idea how to convince the compiler to check this for me with any trick.)
A partial solution could be to make copy() pure virtual in the class Base (assuming it is not meant to be instantiable).
you may wonna change the line of new
Base* c = new Derived(*d);
so you have the type Derived in a Base pointer. During runtime it is looked up, which type it is and you get the right output.
let me know if im wrong... just created this out of my mind on the fly.
To answer your question about whether or not this is copy constructing lets add some members. Base will have a member, m_b and Derived will inherit m_b but also have another member m_d
#include <iostream>
struct Base {
const int m_b;
Base() = delete;
Base(const int a_b) : m_b(a_b) {}
virtual void sayHello() {
std::cout << "Base " << m_b << std::endl;
}
};
struct Derived : public Base {
const int m_d;
Derived() = delete;
Derived(const int a_b, const int a_d) : Base(a_b), m_d(a_d) {}
void sayHello() override {
std::cout << "Derived " << m_b << ' ' << m_d << std::endl;
}
};
void foo(Derived* a) {
Base* b = new Base(*a);
b->sayHello(); // Output is "Base 1", 1 was copied from argument a
}
void bar(Derived* a) {
Base* d = new Derived(*a);
d->sayHello(); // Output is "Derived 1 2"
}
int main() {
Derived d(1, 2);
foo(&d);
bar(&d);
return 0;
}
The line:
Base* b = new Base(*a);
Created a Base and so sayHello calls Base's implementation which doesn't know about m_d. However this line does copy m_b from the derived class
The line:
Base* d = new Derived(*a);
Created a Derived and so sayHello calls Derived's implementation which copied both m_b and m_d
Expected polymorphic behavior will come into existence when the Base class pointer points to Derived class object. Then at run time the actual type of object pointed to by the Base class pointer will be checked and appropriate function will get called.
Base* c = new Base(*d); // <<-- case of object slicing
Here, c points to Base class object. Therefore, c->sayHello() ; is bound to call the Base::sayHello() at runtime.
are we getting an exact copy?. No since you are creating a Base object due to new Base. Due to object slicing the Base part of the *d object is passed to copy c'tor and what you get is corresponding Base object.
Base *c = new Derived(*d); will give the expected behavior.
class Base
{
public:
virtual void print() = 0;
};
class A : public Base
{
int mClassA;
public:
A() : mClassA(1) {}
void print() override { std::cout << "print A" << std::endl; }
void foo( A& arg ) { std::cout << mClassA << std::endl; }
};
class B : public Base
{
int mClassB;
public:
B() : mClassB(2) {}
void print() override { std::cout << "print B" << std::endl; }
void foo( B& arg ) { std::cout << mClassB << std::endl; }
};
So I got class structure similar to this. What approach should I take to call foo without dynamic_cast each time?
int main()
{
Base * obj1 = new A();
Base * obj2 = new A();
dynamic_cast<A*>(obj1)->foo(*dynamic_cast<A*>(obj2));
}
I could create foo method with base class argument but I want to be sure that I'm passing A or B obejct as an argument.
You could use templates to make sure that a particular parameter of one of the class' member functions has at least a particular type. See the following code illustrating this:
template <class P>
class Base
{
public:
Base(int nr) : mClass(nr) {}
virtual void print() = 0;
virtual void foo( P& arg ) { std::cout << mClass << std::endl; }
protected:
int mClass;
};
class A : public Base<A>
{
public:
A() : Base(1) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( A& arg ) override { Base::foo(arg); cout << "is A for sure" << endl; }
};
class B : public Base<B>
{
public:
B() : Base(2) {}
void print() override { std::cout << "print A" << std::endl; }
virtual void foo( B& arg ) override { Base::foo(arg); cout << "is B for sure" << endl; }
};
int main()
{
Base<A> * obj1 = new A();
A* obj2 = new A();
obj1->foo(*obj2);
Base<B> * objb1 = new B();
B* objb2 = new B();
objb1->foo(*objb2);
// objb1->foo(*obj2);
// Non-const lvalue reference to type 'B' cannot bind to a value of unrelated type 'A'
}
It sounds like you're wanting to do something like this:
class Base
{
public:
virtual void foo(Base&) = 0;
};
class A : public Base
{
public:
void foo(A&);
};
class B : public Base
{
public:
void foo(B&);
};
In object oriented design, this is known as covariance (specifically, a "covariant method argument type").
The problem is that this goes against principles of good object oriented design. The Liskov substitution principle says that, if you have a base class Base, then any instances of subclasses of Base need to be interchangeable - but you want some subclasses of Base to not work with other subclasses of Base. (This is an oversimplification, but there are plenty of discussions online with more detail.)
If you want to do this - if it's the best solution in your case, in spite of the general advice of the Liskov substitution principle - then you can implement the checks yourself.
void A::foo(Base& base_arg) {
// This will throw a runtime exception if the wrong type
A& arg = dynamic_cast<A&>(base_arg);
std::cout << mClassA << std::endl;
}
Note that you're sacrificing some compile-time type safety now - if you accidentally try to call A::foo with an instance of B, you won't know until the code runs and you get an exception. (That's the whole point of virtual functions / dynamic dispatch / polymorphism - the behavior is determined at runtime.)
Another approach would be to use templates, like #Stephen Lechner's solution. That gives up runtime polymorphism, but it keeps strong type safety and better follows conventional OO design.
The Wikipedia article on covariance has a lot more discussion, including further example code.
I'm struggled over some code where I don't know how to name it and how to solve it. I tried to reduce the code to the following example (so the example itself won't make sense, but it shows the problematic):
struct MyInterface {
virtual ~MyInterface() {
};
virtual void Output() = 0;
};
class A {
public:
MyInterface *myInterface;
A(MyInterface *myInterface) {
std::cout << "this in A constructor: " << this << std::endl;
this->myInterface = myInterface;
}
void CallA() {
this->myInterface->Output();
}
};
class B : public MyInterface, A {
public:
int v;
B(int v) : A(this) {
std::cout << "this in B constructor: " << this << std::endl;
this->v = v;
}
virtual void Output() override {
std::cout << "Whatever" << std::endl;
}
void CallB() {
std::cout << "this in CallB: " << this << std::endl;
this->CallA();
}
};
class Foo {
public:
B b;
Foo() : b(42) {
b = B(41); //This will make an "invalid" B:
//generates B on the Stack but assign the bytes to Foo.b (which is on the the heap)
//so b.myInterface will point to the stack
//after leaving this context b.other will be invalid
}
void Exec() {
b.CallB();
}
};
int main(int argc, char **args) {
Foo *foo = new Foo();
foo->Exec(); //Gives a segfault, because foo->b.myInterface is not valid
return 0;
}
First I thought it has something to do with the inheritance and its virtual methods. But I think the main problematic is the this pointer within the constructors.
So my questions: When b is constructed, the this pointer in the constructors points to the stack. Why doesn't show the this pointer to the target memory (in the heap)? No copy constructor is called - Why?
How can I Name this problem?
The copy constructor isn't called because you aren't creating a new object you are assigning to an existing object. This calls the assignment operator.
This is copy construction:
B b1(42); // construction
B b2(b1); // copy construction
B b3 = b1; // looks like assignment but is actually copy construction
This is assignment:
B b1(42); // construction
b1 = B(43); // b1 already exists we can't copy construct, construct a new object and assign to b1
You need to override the assignment operator:
class B
{
B& operator=(const B& other)
{
// fix references to this here
}
}
So I'm having a little bit of problems understanding how I should fix this polymorphic issue I've ran into. To make things short, let's define only two levels of classes, a father and two sons:
The parent:
class Entity {
public:
int x;
Entity();
~Entity();
Entity(const Entity&);
Entity &operator=(const Entity&);
};
The two sons:
class EntitySon1 : public Entity {
public:
int b;
EntitySon1();
~EntitySon1();
EntitySon1(const EntitySon1&);
EntitySon1 &operator=(const EntitySon1&);
};
class EntitySon2 : public Entity {
public:
int a;
EntitySon2();
~EntitySon2();
EntitySon2(const EntitySon2&);
EntitySon2 &operator=(const EntitySon2&);
};
Please, forget the fact that in this example all classes only have an int value and the standard operator= should therefore be enough, in the real project these classes are more complex so I do have the need to implement one myself and they are succesfully calling parent ones as well.
So now, somewhere in my project, I have an array of Entity*, which can only be either son1 or son2. I want to go through this array of entities and make copies into another array. The code I'd like to be able to write is something like:
for (i = 0; i < entities; ++i) {
entityCopiesArray[i] = entitiesArray[i];
}
Problem is, both entityCopiesArray and entitiesArray are of type (Entity*) so when the assign is done, only Entity.operator=() gets called, while I need, in the case that current Entity is son1, have both Entity.operator=() and EntitySon1.operator=() called.
I know I can cast each variable on the array so the right operator gets called, but that needs extra information to tell which entities are son1, which are son2, and also need to be typed manually for every possible Entity's son.
Is there any other way around this, or am I stuck with doing:
if (isSon1())
(EntitySon1)entityCopiesArray[i] = (EntitySon1)entitiesArray[i];
else if (isSon2())
(EntitySon2)entityCopiesArray[i] = (EntitySon2)entitiesArray[i];
// ... etc
edit: I made this post late night and tried to compact the information as much as possible so I said things that weren't accurate. I obviously have an array to Entity*, else I wouldn't be able to use polymorphism.
Consider the following:
struct Base {
int a;
};
struct Derived1 : public Base {
int d1Data[100];
};
struct Derived2 : public Base {
char d2Data[1500];
};
Now if we do the following:
Entity* e = new Entity;
Derived1* d1 = new Derived1;
Derived2* d2 = new Derived2;
std::cout << sizeof(*e) << ", " << sizeof(*d1) << ", " << sizeof(*d2) << '\n';
What will the output be? Hint: The numbers are not going to be the same.
So now what happens in each of the following cases?
*e = *(Entity*)d1;
*(Derived1*)e = *d1;
*(Derived2*)d1 = *d2;
*(Entity*)d1 = *(Entity*)(d2);
*(Derived1*)d2 = *d1;
None of these cases is particularly good. Your post makes it sound like you are setting yourself up for a bad case of object slicing.
DO NOT DO.
On the other hand, if what you are looking to do is to clone objects from a list:
std::vector<Base*> entities;
std::vector<Base*> copies;
entities.push_back(new Derived1);
entities.push_Back(new Derived2);
for (size_t i = 0; i < entities.size(); ++i) {
Base* clone = make_a_copy_of(entities[i]);
}
then the way to do this is to add a member function to Base.
struct Base {
int a;
virtual Base* clone() const = 0;
};
struct Derived1 : public Base {
int d1Data[100];
Base* clone() const override {
return new Derived1(*this);
}
};
struct Derived2 : public Base {
char d2Data[1500];
Base* clone() const override {
return new Derived2(*this);
}
};
int main() {
std::vector<Base*> entities;
std::vector<Base*> copies;
entities.push_back(new Derived1);
entities.push_Back(new Derived2);
for (size_t i = 0; i < entities.size(); ++i) {
Base* clone = entities[i]->clone();
}
// remember to delete all the objects we allocated,
// or wrap them with std::unique_ptr
return 0;
}
I will probably be scowled at for using raw pointers like this without using something like std::unique_ptr to ensure the objects have a lifetime, so here is a complete version using unique_ptr. I'm not using make_unique because neither my GCC (4.8.2) or MSVC appear to support it.
#include <iostream>
#include <vector>
#include <memory>
struct Base {
int m_a;
Base(int a) : m_a(a) {}
virtual ~Base() { std::cout << "Dtoring " << m_a << '\n'; }
virtual std::unique_ptr<Base> clone() const = 0;
};
struct Derived1 : public Base {
int d1Data[100];
Derived1(int a) : Base(a) {}
virtual ~Derived1() { std::cout << "D1 at " << (void*)this << " dtord\n"; }
std::unique_ptr<Base> clone() const override { return std::unique_ptr<Derived1>(new Derived1 (*this)); }
};
struct Derived2 : public Base {
char d2Data[10000];
Derived2(int a) : Base(a) {}
virtual ~Derived2() { std::cout << "D1 at " << (void*)this << " dtord\n"; }
std::unique_ptr<Base> clone() const override { return std::unique_ptr<Derived2>(new Derived2 (*this)); }
};
int main()
{
std::vector<std::unique_ptr<Base>> entities;
{
std::vector<std::unique_ptr<Base>> copies;
entities.emplace_back(new Derived1 (3));
entities.emplace_back(new Derived2 (5));
for (auto& ent : entities) {
copies.emplace_back(ent->clone());
}
std::cout << "copies going out of scope\n";
}
std::cout << "entities going out of scope\n";
return 0;
}
Live demo: http://ideone.com/lrgJun
---- EDIT ----
When you inherit a class, you also inherit it's data members into your overall structure. In this example, the effective structure of Derived1 is:
struct Derived1 {
int a; // from Base
int d1Data[100];
};
My implementation of clone is quietly relying on the copy constructor which is essentially doing a memory copy of src to dest, the equivalent of memcpy(this, src, sizeof(*this));. Because of this you don't need to chain calls to clone or anything like that, the magic is done in the copy constructor.
If you need to add instances of Base into your mix, we can implement the clone member in Base - but bear in mind that any "special" members you add to Base are going to be inherited in all the derived classes too.
I'll convolute the classes a little and show you what the copy constructors for Base and Derived1 effectively look like:
struct Base {
int m_int;
double m_double;
std::string m_name;
private:
unsigned int m_baseOnly;
...
};
struct Derived1 : public Base {
// inherited m_int, m_double and m_name
// also inherited m_baseOnly, we just can't access it.
std::array<int, 100> m_data;
std::string m_title;
std::shared_ptr<Base> m_buddy;
...
};
At this point, the actual in-memory structure of a Derived1 looks like this:
Derived1 {
int m_int;
double m_double;
std::string m_name;
unsigned int m_baseOnly;
std::array<int, 100> m_data;
std::string m_title;
std::shared_ptr<Base> m_buddy;
};
Given these definitions, unless we implement our own copy constructor or disable copy construction, this is effectively what the compiler will generate for us:
Base::Base(const Base& rhs) // Base copy constructor
: m_int(rhs.m_int)
, m_double(rhs.m_double)
, m_name(rhs.m_name)
, m_baseOnly(rhs.m_baseOnly)
{
}
Derived1::Derived1(const Derived1& rhs)
: Base(rhs) // copy-construct the Base portion
, m_data(rhs.m_data) // hence why I used std::array
, m_title(rhs.m_title)
, m_buddy(rhs.m_buddy)
{
}
My implementation of clone for Derived1
std::unique_ptr<Base> clone() const override
{
return std::unique_ptr<Derived1>(new Derived1 (*this));
}
or
std::unique_ptr<Base> clone() const override
{
const Derived1& rhs = *this; // Reference to current object.
Derived1* newClone = new Derived1(rhs);
return std::unique_ptr<Derived1>(newClone);
}
which is creating a new Derived1, invoking the new, empty, clone's copy-ctor with the current object as rhs and filling out the clone.
I have an array of Entities, which can only be either son1 or son2.
In general this is not possible. But you can have an array of Entity*, each of which points to a Son1 or a Son2. Then you can have a virtual clone function such that a member of this family creates a copy of itself and returns a pointer (of type Entity*) to it. Then you can copy the array quite easily.