static_cast between 'unrelated types' - c++

If I have this class structure:
class A
{
public:
int a;
void funcA(){a = 0;}
};
class B
{
public:
int b;
void funcB(){b = 0;}
};
class C: public A, public B
{
public:
int c;
void funcC(){c = 0;}
};
Why can I perform this cast?
A* pA = new A;
C* pC = static_cast<C*> (pA);
B* pB = static_cast<B*> (pC);
pB->funcB();
A and B are unrelated, are they not?

They may be unrelated, but the compiler doesn't do inter-cast diagnosis here.
It just says "Oh, C is a derived class of A, that's legal as far as I'm concerned".
In the next line it says "Oh, B is a base class of C, that's legal as far as I'm concerned".
And that's about it. In your case, C links A and B between casts.

Related

dynamic_cast fails when cast a derived class to base class

In Primer c++ 5th
class A {
public:
A() : a(1) {}
virtual ~A() = default;
private:
int a;
};
class B : public A {
public:
B() : b(2) {}
private:
int b;
};
class C : public B {
public:
C() : c(3) {}
private:
int c;
};
//class D : public B, public A { cause error
// public:
// D() : d(4) {}
// private:
// int d;
//};
int main()
{
//A *pa = new C;
//B *pb = dynamic_cast<B*>(pa); //1st case
B *pb = new B;
C *pc = dynamic_cast<C*>(pb); //2nd case
cout << pc << endl;
//A *pa = new D;
//B *pb = dynamic_cast<B*>(pa); //3rd case
}
//output: 0 cast failure
Q1:
Here in the above code .I can understand why the 2nd case doesn't work, but
the type of pb-pointed object is B which is the public base class of C .And this is the 2nd situation of what's said in Primer c++.
So why the 2nd case doesn't work while primer c++ said this kind of cast will succeed?
Q2:
the 3rd case. Errors occurred during compilation
error: ā€˜Aā€™ is an ambiguous base of ā€˜Dā€™
What does this error mean?
in your second example you create a class B, B is a base class for C.
so you can't cast a base class to some derived class.
this will work:
B *pb = new C();
C *pc = dynamic_cast<C*>(pb);
regarding 3rd example D derive from B and A, but B also derive from A, this make problems for compiler. you try to derive 2 times for A, the compiler will not know what function A to use, the base A or the derived version of B.
al
you should read more about base and derived classes.

what does compiler do when new an object and assign the address of the created object to its base class pointer

Example 3:(page 377)
class A {virtual void f();};
class B {virtual void f(); virtual void g();};
class C: A, B {void f();};
A* pa = new C;
B* pb = new C;
C* pc = new C;
pa->f();
pb->f();
pc->f();
pc->g()
(1) In Multiple inheritance for C++, Bjarne wrote: On entry to C::f, the this pointer must point to the beginning of the C object (and not to the B part). However, it is not in general known at compile time that the B pointed to by pb is part of a C so the compiler cannot subtract the constant delta(B).
Why does the compiler not know that B pointed to by pb is part of a C at compile time? Based on my understanding, B pointed to by pb is definitely a part of C since we new C and C inherits from B!
What about B* pb = new B;? does the compile know B pointed to by pb is a standlone object?
Let's make a few minor changes to your code:
struct A {virtual void f() {}};
struct B {virtual void f() {} virtual void g() {}};
void foo(B* bp)
{
bp->f();
}
In the above call, there is no way of knowing which sub-type of B bp points to. It could be C, D, or something else. If you step into the call you would know which sub-type of B bp points to.
struct C : A, B {void f() {}};
struct D : B {void f() {}};
int main()
{
B* pb1 = new C;
B* pb2 = new D;
foo(pb1);
foo(pb2);
}

Does a member of a C++ base class really needs to be virtual to be overridden by a derived class?

class A {
public:
virtual int test()=0;
};
class B : public A {
public:
int test(){return 10;}
};
B *b = new B();
b->test(); // would return 10;
whereas:
class A {
public:
int test(){return 0;}
};
class B : public A {
public:
int test(){return 10;}
};
B *b = new B();
b->test(); // **would return 0**;
Why does it return "0" here? This makes zero sense to me, because I assume that the (kind of overloaded) members of the derived class (B) come first!
What is happening here?
Apart from the invalid syntax (B->test(); where it should be b->test();), the second one will also return 10.
If instead you would have written:
A* a = new B();
a->test();
It would have returned 0 or 10 depending on whether A::test is virtual.

Multiple inheritence, selecting which virtual function to call

I have the following code sample:
class A
{
public:
A(int a):AA(a) {};
int AA;
virtual int Test()
{
return AA;
};
};
class B
{
public:
B(int b):BB(b) {};
int BB;
virtual int Test()
{
return BB;
};
};
class C:public A, public B
{
public:
C(int a, int b, int c) :A(a),B(b),CC(c) {};
int CC;
};
int main()
{
A *a = new C(1,2,3);
B *b = new C(1,2,3);
C *c = new C(1,2,3);
int x = a->Test() ; // this is 1
int y = b->Test() ; // this is 2
// int z = c->Test() ; // this does not compile
return 0;
}
I was expecting the calls to a->Test() and b->Test() to be ambiguous too as the object a is a C and therefore inherits from A and B both of whom have identical Test() functions. However, they both call the implementation which corresponds to the delcared type rather than the type that the object actually is.
Can anyone explain why these calls are not ambiguous?
Does C++ always behave this way?
In fact,a C instance is both a full A instance and a full B instance (so holds a copy of A methods & B methods)
Since a is a A* , the compiler will use the A virtual table copy that is inside of the C instance
Since b is a B* , the compiler will use the B virtual table copy that is inside of the C
instance
you cannot use C* since the compiler will not now which Test() method of A or B you want to call (since the C class holds both A::Test & B::Test symbols)
if you implement a C::Test() method, then it will be called both instead of A::Test() & B::Test() since method is virtual for both A & B.
Because A does not know anything about the existence of C.
Consider a slightly different scenario:
foo.h
class A { public: virtual void Test() {} };
void myFunction(A *a);
foo.cpp
#include "foo.h"
void myFunction(A *a) {
a->Test();
}
You would expect this to compile, I guess? But what if I later independently inherited from A, should that affect whether this code compiles?

conversion from derived * to base * exists but is inaccessible

Why does the follwing code produce this error even though c is a struct and has a public inheritance by default??
struct c
{
protected:
int i;
public:
c(int ii=0):i(ii){}
virtual c *fun();
};
c* c::fun(){
cout<<"in c";
return &c();
}
class d : c
{
public:
d(){}
d* fun()
{
i = 9;
cout<<"in d"<<'\t'<<i;
return &d();
}
};
int main()
{
c *cc;
d dd;
cc = &dd;
cc->fun();
}
You need:
class d : public c
class inheritance is private by default.
When you privately inherit from a class or a struct, you explicitly say, among other things, that direct conversion from a derived type to a base type isn't possible.