I'm working on an assignment involving 4 classes and diamond inheritance. I've based all my answers on an assumption that may or may not be correct.
The diamond hierarchy is like this:
A
/ \
B C
\ /
D
and the code looks like this:
class A
{
private:
string s;
public:
A(string s);
virtual ~A;
virtual void set(string s);
virtual string get();
};
class B : public virtual A
{
public:
void set(string s);
string get();
}
class C : public virtual A
{
public:
void set(string s);
}
class D : public B, public C
{
public:
void set(string s);
}
Suppose I have a pointer that looks like this:C *obj = new D();
If get is called on obj, the pointer will actually end up looping back to D and then invoke B's get method. A C object alone would end up invoking A's get method. Assuming B and A's get methods return different results, which result would be expected?
The code you provided unfortunately won't compile as is.
We can create a similar example and just try it:
#include <cstdio>
struct A
{
virtual char const * get() {return "a";};
virtual ~A() = default;
};
struct B : public virtual A
{
char const * get() override {return "b";};
};
struct C : public virtual A
{
//char const * get() override {return "c";};
};
struct D : public B, public C
{
//char const * get() override {return "d";};
};
int main()
{
A* a = new A();
B* b = new B();
C* c = new C();
C* d = new D();
printf("%s\n", a->get());
printf("%s\n", b->get());
printf("%s\n", c->get());
printf("%s\n", d->get());
delete a;
delete b;
delete c;
delete d;
}
which gives:
a
b
a
b
isocpp calls this delegating to a sister class
As B and C both virtually inherit A, there is only a single instance of A, therefore in the virtual table, when B overrides an implementation of A, only a single member overrides get and this becomes also overridden for D.
Should you also uncomment the the get method in C, then we would get:
virtual.cc:19:8: error: no unique final overrider for 'virtual const char* A::get()' in 'D'
19 | struct D : public B, public C
|
However, further modifying the example and also uncommenting the get in D would make the code compile again. Now returning:
a
b
c
d
It will act like a D object.
Just like with single inheritance, it acts like the class that was created (not what the pointer to it is).
Related
class A {
private:
char a;
char sub_f(char *);
public:
A();
char f(char* ) {some actions using sub_f(char*);}
};
class B {
private:
char b;
public:
B();
void execute() { b = f("some text");} //PROBLEM IS HERE
}
Can smb explain me how can I call f(char *) function which is a member of class A, from the void B::execute() ? I can't compile it right now. If I make f(char*) a friend function of the class A, there is another problem appear :
friend f(char*) doesn't know anything about private function sub_f(char*) .
I am a beginner in C++ and will be appreciate for full answers with explanation.
If you have a public member function, like
class A {
public:
char f(char* );// {some actions using sub_f(char*);}
};
you can call it on an instance
A a;
char just_one_char = a.f("Whatever");
The same applies across the board - to call this member function you need an instance.
One approach would be to make your class B have a member variable of type A:
class B {
private:
char b;
a a;
public:
B();
void execute() { b = a.f("some text");} //PROBLEM Solved
};
If f doesn't need any instance data from class A it could be static, or a free function.
Perhaps there isn't a one-to-one relationship between B and A like this.
Perhaps execute could make an A when it needed to:
class B {
private:
char b;
public:
B();
void execute() {
A a;//just needed for this function call, rather than lifetime of B
b = a.f("some text"); //PROBLEM is solved a different way
}
};
I have an object that is referenced by a pointer to its superclass: Base* d1 = new Derived();
I would like to pass it to another method that expects an object of the derived class: void f(Derived* d);
But it doesn't work unless I use type-casting. Is there another way to achieve this?
Here is an example:
#include <stdio>
class Base {};
class Derived : public Base {};
class Client
{
public:
void f(Base* b) { printf("base"); };
void f(Derived* d) { printf("derived"); };
};
int main(int argc, char* argv[])
{
Client* c = new Client();
Base* b = new Base();
Base* d1 = new Derived();
Derived* d2 = (Derived*) d1;
c->f(b); // prints "base". Ok.
c->f(d1); // prints "base"! I expected it to be "derived"!
c->f(d2); // prints "derived". Type-casting is the only way?
}
Generally speaking, you can do some stuff with dynamic_cast.
From the other side I believe, that dynamic_cast can practically always be avoided by the good design.
In your example you can make function f virtual member of Base class and override it in the Derived class. Then call it f via pointer to Base.
Something like this:
class Base {
public:
virtual void f() {
printf("Base\n");
}
};
class Derived : public Base {
public:
virtual void f() {
printf("Derived\n");
}
};
class Client
{
public:
void f(Base* b) {
b->f();
};
};
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.
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?
I have this
A
/ \
B C
\ /
D
A has a pure virtual function, prototyped as:
virtual A* clone(void) const = 0;
B and C virtually inherit from A ( class B: public virtual A, class C: public virtual A)
B has the virtual function, prototyped as:
virtual B* clone(void) const {};
C has the virtual function, prototyped as:
virtual C* clone(void) const {};
D inherits from both B & C like that: class D: public B, public C
D has the virtual function, prototyped as:
virtual D* clone(void) const {};
Now, when compiling I get the following 6 lines of errors:
error C2250: 'D' : ambiguous inheritance of 'B *A::clone(void) const'
No freaking idea how to solve this issue.
Thanks in advance.
Use virtual inheritance if you want only one copy of a parent in your hierarchy.
class B : public virtual A
Edit:
There may be a bug in MSVC++ 2010. The Intellisense doesn't detect a problem, but the compiler chokes on it. Strange since VC6 is happy enough with it.
As a workaround, if you declare D as follows, it makes MSVC++ 2010 happy while also working in compilers without this issue:
class D: public virtual A, public B, public C
What you describe in your original post is perfectly legal. A quick sample code that does exactly that compiles without any errors by Comeau Online compiler
class A {
public: virtual A* clone() const = 0;
};
class B: public virtual A {
public: virtual B* clone() const { return 0; }
};
class C: public virtual A {
public: virtual C* clone() const { return 0; }
};
class D: public B, public C
{
public: virtual D* clone() const { return 0; }
};
Either you are not doing what you said you are doing, or your compiler is broken. Post real code you are trying to compile.
P.S. I just tried compiling this in VS 2010 Express and got the same error. As Gunslinger47 also suggests in the comments, this is a bug in VS 2010 compiler.
avoid diamond inheritance? ;->
anyway, here is sample (really sample - don't cast like that)
// ConsoleCppTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include "iostream"
class A {
public:
virtual void* clone() = 0;
};
class B: public A {
public:
virtual void* clone() = 0;
};
class C: public A {
public:
virtual void* clone() = 0;
};
class D: public B, public C
{
public:
virtual void* B::clone()
{
std::cout << "B";
return (void*)this;
}
virtual void* C::clone()
{
std::cout << "C";
return (void*)this;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
D* d = new D();
void* b = ((B*)d)->clone();
void* c = ((C*)d)->clone();
return 0;
}