#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; }
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.
Suppose there is a class A which has two subclasses, Aa and Ab. I want to make an array that can store pointers to objects of class Aa and Ab. If an array is declared with the type of class A, is this valid? If not, how can I accomplish this? For example:
A *arr;
//space allocated
Ab *obj1;
arr[x] = obj1;
On a related note, I want to write a function that when given a location, will return the object stored at that location in the array. If the above works and I have an array of objects of either Aa or Ab, the function could return an object of either type Aa or Ab. If the return type of the function is specified as A, the superclass, is this valid? If not, I have looked at template functions but cannot find a straight answer about just having the return type be variable, not the parameters. For this example, the function's parameter is always going to be int, but it could return an Aa or an Ab, depending on what is at that location in the array.
Yes that is the way polymorohism is achieved (using pointer to base class) and virtual methods.
Here is an example:
#include <iostream>
using namespace std;
#include <vector>
class A{
public:
virtual void foo()const{
std::cout << "A::foo()" << std::endl;
}
};
class Aa : public A {
public:
virtual void foo()const{
std::cout << "Aa::foo()" << std::endl;
}
};
class Ab : public A {
public:
virtual void foo()const{
std::cout << "Ab::foo()" << std::endl;
}
};
int main(){
A* ptrA[3];
A* a = new A;
Aa* aa = new Aa;
Ab* ab = new Ab;
ptrA[0] = aa;
ptrA[1] = ab;
ptrA[2] = a;
for(int i(0); i != 3; ++i)
ptrA[i]->foo();
delete a;
delete aa;
delete ab;
return 0;
}
Remember that C++ is Invariant not Contravariant which means you cannot assign a derived object a base object:
A* a = new A;
Ab* ab = a; // error
Is valid to have an array of base pointers, also you can use dynamic_cast to know in run time the return type of your array and use the API from the derived class. See and example below.
struct Base { virtual void do_something() {} };
struct Derived1 : Base
{
void first() const { std::cout << "first" << std::endl; }
void do_something() override {}
};
struct Derived2 : Base
{
void second() const { std::cout << "second" << std::endl; }
void do_something() override {}
};
Base& get(int option)
{
static std::vector<Base*> b {new Derived1{}, new Derived2{}};
return !option ? *b[0] : *b[1];
}
int main()
{
const int option {0};
// const int option {1};
if (Derived1* derived {dynamic_cast<Derived1*>(&get(option))})
{
derived->first();
}
else if (Derived2* derived {dynamic_cast<Derived2*>(&get(option))})
{
derived->second();
}
}
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.
If I have class A, and class B which subclasses A, should typeid(x) give the type of A or the type of B, if x is given by:
A *x = new B();
In my tests I get the type of A - which is not very useful - but I'm not sure if that's due to how C++ works, or if this is due to compiler settings?
Example code:
#include <iostream>
#include <typeinfo>
// Remember to add a virtual member function in A
// to enable RTTI.
struct A { virtual ~A() {} };
struct B : A { virtual ~B() {}};
int main()
{
A* ap = new B();
std::cout << typeid(ap).name() << std::endl;
std::cout << typeid(*ap).name() << std::endl;
}
Output, with g++ 4.8.2:
P1A
1B
Assume the following simple case (notice the location of virtual)
class A {
virtual void func();
};
class B : public A {
void func();
};
class C : public B {
void func();
};
Would the following call call B::func() or C::func()?
B* ptr_b = new C();
ptr_b->func();
Your code is invalid C++. What are the parentheses in class definition?
It depends on the dynamic type of the object that is pointed to by pointer_to_b_type.
If I understand what you really want to ask, then 'Yes'. This calls C::func:
C c;
B* p = &c;
p->func();
Examples using pointers as well as reference.
Using pointer
B *pB = new C();
pB->func(); //calls C::func()
A *pA = new C();
pA->func(); //calls C::func()
Using reference. Note the last call: the most important call.
C c;
B & b = c;
b.func(); //calls C::func()
//IMPORTANT - using reference!
A & a = b;
a.func(); //calls C::func(), not B::func()
Online Demo : http://ideone.com/fdpU7
It calls the function in the class that you're referring to. It works it's way up if it doesn't exist, however.
Try the following code:
#include <iostream>
using namespace std;
class A {
public:
virtual void func() { cout << "Hi from A!" << endl; }
};
class B : public A {
public:
void func() { cout << "Hi from B!" << endl; }
};
class C : public B {
public:
void func() { cout << "Hi from C!" << endl; }
};
int main() {
B* b_object = new C;
b_object->func();
return 0;
}
Hope this helps