#include <iostream>
struct A {
virtual void a() {
puts("A");
}
};
struct B {
virtual void b() {
puts("B");
}
};
struct C {
virtual void c() {
puts("C");
}
};
struct D : public A, public B, public C {
virtual void c() {
C::c();
puts("cd");
}
};
int main() {
A* obj = new D;
obj->a();
B* b = (B*)obj;
b->b();
C* c = (C*)obj;
c->c();
return 0;
}
I have this code where I have non virtual multiple inheritance. However, it seems to call the wrong virtual function when I call the functions in the main function.
Instead of outputting:
A
B
C
cd
It outputs:
A
A
A
What puzzles me is that when I change the code to doing this:
B* b = (B*)(D*)obj;
b->b();
C* c = (C*)(D*)obj;
c->c();
It outputs what I would expect (see above). Afaik doing a double pointer cast like this wouldn't effect anything and would be optimized out by the compiler. But it seems to be changing what virtual function is being called.
Can someone explain why this would change what virtual function is being called?
Notes:
I printed the pointers at each step, they are the same.
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
Can someone explain why this would change what virtual function is being called?
Generally, a C-style cast between pointer types won't change the value of the pointer and so will have no effect. There is, however, one exception.
A cast between a class and a parent or child class can change the value of the pointer. For example:
class A
{ int a; };
class B
{ int b; };
class C : public A, public B
...
Now, a pointer to an instance of class A will probably have the same value as a pointer to its a member and a pointer to an instance of class B will probably have the same value as a pointer to its b member. A pointer to an instance of class C can't have the same value as a pointer to both its A::a and its B::b members since they're distinct objects.
A function expecting a B* can be passed a C* since a C is a B. Similarly, a function expecting an A* can be passed a C* for the same reason. But at least one of these will require a value change to the pointer.
So casts between these types will change the values, the others are all no-ops.
Of course, all of this is UB. You are casting between unrelated types and then dereferencing them.
I want to avoid using dynamic_cast (although it does work) as it's too slow for what I need it to do.
That seems very hard to believe.
Related
Why does this compile, if A has no virtual functions?
class A {
int a = 42;
};
class B {
void* f() {
return dynamic_cast<A*>(this);
}
virtual void my_virtual() {};
};
Note: Though it makes no sense to write something like this, this was the result of a refactor, after the base class was removed. I feel like there should have been a compiler error.
Because it's not a requirement, and it shouldn't be an error.
Consider the following addition to your classes (after making B::f() public):
class C: public A, public B
{
};
int main()
{
C c;
void* p = c.f();
}
which should, and does, return to p a pointer to the A subobject of c.
Only the conversion source is required to be of polymorphic type, and that is only if it is not known at compile time that the target is a base class of the source.
In the latter case, a decent compiler will not do any conversion at runtime.
Virtual function d() in the base class A is overidden by a private method in derived class B. When d() is invoked on an instance of B from outside, via a pointer of type A *, it is B::d() that runs, even though it is private to B.
Why does this happen? Shouldn't it be impossible for code outside B to invoke B's private methods?
Demo
#include<iostream>
using namespace std;
class A {
public:
virtual void d(){
cout<<" gfgd ";
}
};
class B :
public A
{
private:
void d(){
cout<<"hytyhtht";
}
};
int main() {
A *a1;
B b;
a1=&b;
a1->d();
return 0;
}
Output:
hytyhtht
The public/protected/private access-rules are enforced at compile-time, not at run-time, which means that they have to rely on logic that the compiler can enforce at compile-time.
In particular, the compiler knows that you are calling the d() method using a A* pointer, and that class A has declared virtual void d() to be a public method, so that means it's okay to call the method.
In general the compiler can't know at compile-time that your pointer is really pointing to a B object, so even if it wanted to it wouldn't be able to flag the call as a compile-time error. (Well, maybe in your particular example it could, but in many cases the compiler doesn't know what the type of the pointer-to object will be, it only knows the type of the pointer)
For example:
// in someotherfile.cpp
void MyFunction(A * a)
{
a->d(); // should this compile, or not?
}
Similar, but not identical to, THIS QUESTION:
A
/ \
B C
\ /
D
What I want is:
struct A { virtual void func (void) = 0; };
struct B : virtual A { void func (void) {} };
struct C : virtual A { void func (void) {} };
struct D : B,C { void func (void) {} };
int main ()
{
A *p = new D();
((C*) p)->func(); // do C::func
((B*) p)->func(); // do B::func
}
According to THIS QUESTION this does not seem to be a problem so long the inheritance is just multiple inheritance and not a diamond. why does this not work with a diamond shape?
Apparently its ambiguous, but what I want to be able to do is cast the pointer and hence use a different parent implementation of the virtual function, i.e.:
((C*) p)->func(); //does C::func
If I run the code above I run into the error:
error: cannot convert from pointer to base class 'A' to pointer to derived class 'C' because the base is virtual
((C*)p)->func();
which I tried to google but cannot find anywhere
Since func is virtual throughout the hierarchy, any direct call to func through a pointer to any of the types involved will call D::func. To do the cast in the code in the question, use dynamic_cast<C*>(p). But that doesn't remove the virtual-ness of func, so that will end up calling D::func, just as p->func() does.
To get rid of the virtual-ness, you have to name the class as well as the function. In a simpler context:
D *d = new D;
d->C::func(); // calls C::func
When you have a pointer to the base type instead of a pointer to the derived type you have to convert the pointer to a type that has C::func. That conversion is done with dynamic_cast, like this:
A *p = new D;
dynamic_cast<C*>(p)->C::func();
Depending on your compiler, you might have to fiddle with your class definitions a bit to get rid of linker errors. Some compilers get confused with inheritance from classes with no non--inline functions.
I have classes A, B, C.
B and C are derived from A. B has a function foo().
If I make an A* array and fill it with B*-s and C*-s then I can't call foo() on the B* element because the compiller will search for it in A.
Is there a way to do it, or A must contain a foo() function too?
The function foo() is only known for B objects. This means that you have a pointer to A, you can't be sure the object has such a function or not. This is why the compiler will complain with an error.
The solution to your issue is polymorphism.
Alternative 1: make the function virtual in A
With this approach, you'd have an empty foo() function that does nothing for all A and C objects, but you'd override with the correct function in B.
Example:
struct A {
virtual void foo () { cout<<"nothing!"<<endl; }
};
struct B : A {
void foo () override { cout<<"this is a B object: foo!"<<endl; }
};
struct C : A {};
int main() {
vector<A*> va;
va.push_back (new A);
va.push_back (new B);
va.push_back(new C);
for (auto x : va)
x->foo();
}
Here the online demo
For the records, I've use a vector of pointers instead of an array. But the principle is the same.
Note also that a rule of thumb is that, if you have a virtual function in a class, you should have a virtual destructor as well (I omit it here for the sake of simplicity).
Alternative 2: make the class polymorphic and use dynamic_cast
With this approach, you'd define the foo() only for B object. The trick is when you iterate through your container, you check if the object is a B (this requires the object to be polymorphic), and if yes, you invoke the function.
Example:
struct A {
virtual ~A() {}; // to make A and its descendents polymorphic, you need at least one virtual function
};
struct B : A {
void foo () { cout<<"this is a B object: foo!"<<endl; }
};
struct C : A {};
int main() {
vector<A*> va;
va.push_back (new A);
va.push_back (new B);
va.push_back(new C);
for (auto x : va) {
auto maybe = dynamic_cast<B*>(x);
if (maybe) // yes, it's a B*
maybe->foo();
else cout << "still not a B"<<endl;
}
return 0;
}
Here the online demo
The dynamic_cast is an intelligent cast: if the type of the object pointed doesn't match the target type, then dynamic_cast returns nullptr.
Alternative 3: not recommended
The last alternative can be considered if A can't be polymorphic, but if you have a mean knowing an A* to determine if the object is in reaity a B or not. This could be the case, if in A you'd have some information about the type of the object. In this case you could consider a static_cast.
This is however not recommended:
you'd have to manage yourself a way to know the type of the object (so you'd manage manually, what the compiler does automatically when the types are polymorphic).
if you'd make an error in your static_cast, i.e. you think the object is a B but in reality it is not, you'd have an undefined behavior.
I am working on a simple C++ (under Linux) project, which will have pointers to objects. I have class A, class B which extends A, and class C which extends B. Class C has a method (test) that does not exist in A or B.
Is is possible to have a single pointer 'p' that can point to an object of type A, B, and C ? How would I define that pointer?
Secondly, since a.test() doesn't exist, but c.test() does, can my generic pointer 'p' call p->test() ? Will this compile? What if at run time p points to an object of class A and I call p->test()? Is that a runtime error?
Is is possible to have a single pointer that can point to an object of
type A, B, and C ?
I assume you mean "that can either point to an A object or to B object or to a C object", right?
Yes, you can have such a pointer.
How would I define that pointer?
A*
A base-class pointer can point to objects of derived classes.
Secondly, how would I call methods of the object if the pointer can
point to A/B/C classes?
You define a virtual function in A and override it in B and C. Then, when you call the method through your A*, the language will perform dynamic dispatch, i.e. it will automatically call the right method depending on whether your A* points to an A, to a B or to a C.
Do I need to cast them before calling the methods?
No. That would pretty much defeat the purpose of virtual functions.
Here is a complete example:
#include <iostream>
class A
{
public:
virtual ~A() {} // not really needed in this program,
// but almost always needed in real code
// when a class has a virtual function
virtual void method() { std::cout << "A::method\n"; }
};
class B : public A
{
public:
virtual void method() override { std::cout << "B::method\n"; }
};
class C : public A
{
public:
virtual void method() override { std::cout << "C::method\n"; }
};
int main()
{
A a;
B b;
C c;
A* ptr = &a;
ptr->method();
ptr = &b;
ptr->method();
ptr = &c;
ptr->method();
}
Output:
A::method
B::method
C::method