As I understand it, polymorphism with references should work exactly as it does with pointers.
However, consider the following example: the calls to doer() are correctly dispatched when using pointers, but the "B version" seems to be called in both case when using a reference.
I cannot figure out the reason why the following example is behaving in the way it does. Why is the "B version" called in both cases when using a reference?
#include <iostream>
class B;
class C;
void doer(B *x) {
std::cout << "B version" << std::endl;
}
void doer(C *x) {
std::cout << "C version" << std::endl;
}
class A {
public:
virtual ~A() {}
virtual void doit() = 0;
};
class B: public A {
public:
virtual void doit() override {
doer(this);
}
};
class C: public A {
public:
virtual void doit() override {
doer(this);
}
};
int main() {
B b;
C c;
A *a = &b;
a->doit(); // B version gets called, OK
a = &c;
a->doit(); // C version is called, OK
A &d = b;
d.doit(); // B version is called, OK
d = c;
d.doit(); // B version is called again??
}
Here you assign a reference:
A &d = b;
d.doit(); // B version is called, OK
Here you overwrite the object reffered to by d with c (it's no longer the definition of a reference):
d = c;
d.doit(); // B version is called again??
That's the main difference between references and pointers. A reference is like a constant pointer that you can only assign at definition. Afterwards, whenever you use the reference, it means the object you've referred to.
In fact when you do d = c; some slicing occurs. The object d is in fact a B, but the operator= from A is called, copying only member data of A.
Here how to demonstrate this statement:
class A {
public:
...
A& operator= (A a) {
cout << "A::operator=" << endl; // just to show what happens when d=c is called
return *this;
}
};
class B : public A {
public:
int x; // add some variables for B
virtual void doit() override {
cout << "B::doit() " << x << endl;
doer(this);
}
};
class C : public A {
public:
int a,b; // add aditional variables for C
virtual void doit() override {
cout << "C::doit() " << a << ","<<b << endl;
doer(this);
}
};
...
b.x = 123; // put some class specific variables in C
c.a = 222; c.b = 333; // put some class specific variables in C
A &d = b; // assignement of the reference. d reffers to a b object
d.doit(); // B version is called, OK
d = c; // but an A object is copied (so only A subobject of c is taken
// to overwrite A subobject of d)
d.doit(); // B version is called becaus again?? => yes !! because it's still a B
// And you see that the B part of the object is left intact by A::operator=
cout << typeid(d).name() << endl;
// remember at this point that d still refers to b !
References are bound by their referent for their entire lifetime, and, unlike pointers, require initialization. Using the assignment operator calls the assignment operator of the referent, and does not reassign the reference:
A &d = b;
d = c;
Here d = c calls the assignment operator from the base class A subobject contained in d, and copies the A subobject data contained in c.
Related
#include <iostream>
using namespace std;
class A {
public:
virtual void f() = 0;
};
class B : public A {
public:
void f() {cout << "hi" << endl;}
void g() { cout << "bye" << endl; }
};
int main() {
B b;
A &a = b;
a.f(); // prints "hi"
a.g(); // compile error no member g()
return 0;
}
why does a.g() give compile error while a.f() calls B's f()?
At A &a = b; does the compiler somehow set a boundary of where a's aliasing memory ends?
You are attempting to call g() from an instance of A. A does not have an implementation of g(), so it cannot be called through an A object. The fact that a is a reference to a B does not give a access to any functions that A does not know about.
B, on the other hand is-a A, and defines an implementation of the virtual function f(), so the reference a invokes the correct function.
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
}
}
#include <iostream>
using namespace std;
class A
{
public:
void foo() { cout << "foo in A" << endl; }
};
class B : public A
{
public:
void foo() { cout << "foo in B" << endl; }
};
int main() {
A* a = new B;
a->foo(); // will print "foo in A" because foo is not virtual
B* b = new B;
b->foo(); // will print "foo in B" because static type of b is B
// the problem
A* ab;
ab = dynamic_cast<B*>(new B);
ab->foo(); // will print "foo in A" !!!!!
}
Does the 'dynamic_cast' not change the static type of ab? I mean, logically, it seams equivalent to B* ab = new B; because of the casting.. But it does not.
I thought that dynamic cast changes the static type of the object, am I wrong? And if so, what is the difference between:
A* ab = dynamic_cast<B*>(new B);
and
A* ab = new B;
Thanks
You are dynamic_casting to B, but at time of assignment to ab, you are implicitely casting back to A, so the dynamic_cast gets lost again.
The actual type of the object ab is pointing to still remains B, but the pointer the object is accessed with is of type A, so A::foo is selected. It would have been different if foo was virtual, though.
If you call the foo() function from A pointer, foo() of class A will be called. I believe you're looking for a virtual behavior.
If that is the case, declare foo() of class A as:
virtual void foo() { cout << "foo in A" << endl; }
A has a static function A::create() that creates an instance of A, does some initialization, and returns a pointer to it.
I want to create a subclass of A and have a similar create() func:
class B : public A {
public:
static B* create();
int val;
//...
}
in this B::create() function I have to do the following:
B* B::create() {
auto b = (B*)A::create();
b -> val = 0;
//...
return b;
}
Is this the right way to do it? What will happen after the cast?
Follow-up: A has a protected/private constructor, How should I write B::create(), or B's constructor? I do want the vars inherited from A to have the same values as those created by A::create() would have
The cast won't do anything sensible unless A::create() returns a pointer to a B object. If A::create() returns a pointer to an object which isn't a B you have undefined behavior.
In C++ you deal with initialization of objects using constructors: the initialization of base classes is inherited and each derived can do whatever custom initialization it needs to do. Your B::create() would just return a suitably constructed object:
B::B()
: A() // initialize base
, val(0) {
// other initialization
}
B* B::create() { return new B(); }
You could make class B a friend of A like this
class A {
public:
static A* createA();
int varA;
private:
friend class B; // Make B a friend so that B can use private constructor of A
A()
{
cout << "In A constructor" << endl;
varA = 5; // Initialize members of A here
}
};
A* A::createA()
{
return new A;
}
class B : public A {
public:
static B* createB();
int varB;
private:
B()
{
cout << "In B constructor" << endl;
varB = -5; // Initialize members of B here
}
};
B* B::createB()
{
return new B;
}
int main()
{
cout << "Create A" << endl;
A* x=A::createA();
cout << "x->varA is " << x->varA << endl;
cout << endl;
cout << "Create B" << endl;
B* y=B::createB();
cout << "y->varA is " << y->varA << endl;
cout << "y->varB is " << y->varB << endl;
cout << endl;
delete x;
delete y;
}
When a new B is made, the constructor of A get called automatically and the members of A will be initialized.
Output is:
Create A
In A constructor
x->varA is 5
Create B
In A constructor
In B constructor
y->varA is 5
y->varB is -5
Another way is to make the constructor of A protected instead of private.
I'm getting confused why p->a() is calling B::a()?. Is there a paragraph somewhere in the C++ documentation/standard that describes this behavior well?
#include <iostream>
using namespace std;
class A {
public:
A() { cout << "A ctor" << endl; a_instance = this; }
static A *get_instance() { return a_instance; }
static A *a_instance;
void virtual a() { cout << "From base class" << endl; }
};
class B : public A {
public:
B() { cout << "B ctor" << endl; b_instance = this; }
static B *get_instance() { return b_instance; }
static B *b_instance;
void virtual a() { cout << "From derived class" << endl; }
};
A *A::a_instance = 0;
B *B::b_instance = 0;
main()
{
cout << "Create A" << endl;
A ab;
cout << "Create B" << endl;
B abc;
B *ptr = B::get_instance();
A *p = A::get_instance();
cout << "Called from A object type" << endl;
if (p) {
p->a();
}
}
When you create the variable abc, A's constructor sets a_instance to that instance. Despite p being a pointer to an A, since the instance is pointing to a B, it's correctly calling B::a().
To fix this behaviour, you could use the following:
A* A::get_instance()
{
static A a;
return &a;
}
B* B::get_instance()
{
static B b;
return &b;
}
and remove all code that has to do with a_instance and b_instance.
The B constructor calls the A constructor first. That replaces the a_instance that you'd already created.
This chaining of constructors is well defined in the standard. The base is always called first, so that the derived constructor is guaranteed to be working on a valid base object.
What you are experiencing is caused by the design error, which is based on A's constructor initializing the static member using this. Body of this constructor is invoked not only when you are creating the instance of A but also when you are creating the instance of any of its derived classes:
A() { /* ... */ a_instance = this; }
So when you create an instance of type B, before the body of B's constructor is executed, the body of A's constructor is executed at first - this overwrites member a_instance with this within a context of instance of type B, i.e. it makes a_instance to point to this new instance of type B.
What you could do is to place a static variable inside of the getInstance method:
class A
{
public:
static A* getInstance() {
static A s; // <-- instantiated upon first call
return &s;
}
void virtual foo() { std::cout << "From base class" << std::endl; }
protected:
A() { } // <-- protected constructor
~A() { }
A(const A&); // <-- protected copy constructor
A& operator=(const A&); // <-- protected assignment operator
};
then B:
class B : public A
{
public:
static B* getInstance() {
static B s; // <-- instantiated upon first call
return &s;
}
void virtual foo() { std::cout << "From derived class" << std::endl; }
protected:
B() { } // <-- protected constructor
~B() { }
B(const B&); // <-- protected copy constructor
B& operator=(const B&); // <-- protected assignment operator
};
and possible usage:
int main() {
A::getInstance()->foo();
B::getInstance()->foo();
}
that outputs:
From base class
From derived class
B constructor invokes A constructor...