I'm learning C++ and after having read and tested a lot about multiple inheritance, virtual inheritance/methods and diamond design I still have some problems to understand it till the end.
I'm in the diamond design pattern, where class B e C inherit virtual public A and D inherits public B, public C:
A
/ \
B C
\ /
D
All classes implement a private variable std::string _message that I initialize with the following string.
"class-name instance"
Only Class A implements a virtual public display(void) const method too.
void display(void) const{
std::cout << this->_message << std::endl;
}
The main is:
D foo;
foo.display();
The output is:
A instance
However when I "inspect" the element debugging step by step with Xcode I see that inside the D instance I can correctly find a B, a C and A object (just one shared by B and C) with all the different _message correctly assigned.
What I'm doing wrong? Need I override the display() method in D class? But if so, which is the real point of multiple inheritance if I have to re-implements the same method in a derived class?
Your question seems to not be related to the diamond pattern, but is generally about the inheritance model in C++. Most things in C++ are statically bound, so at compile time the compiler fixes what method or member of a certain name is used:
If you access a member of the implicit this object or using a pointer or reference to an object, you will end up accessing a member of the class the pointer or reference has at compile time, no matter whether at runtime there is a derived-class object that has members of the same name. That's why they say you can not override but just shadow members in base classes when you define an equal named member in the derived class.
The same thing is true for non-virtual functions.
The only thing that behaves different is virtual functions. These functions can be overwritten in derived classes, and code that gets handed a pointer-to-base-class can virtual functions of the base class and end up executing implementations given in the derived class.
So the point of virtual functions is not to have the compiler reinterpret a certain function in the context of derived classes (as you seem to understand it), but to make it possible to replace a function in the base class by a different function in the derived class.
To go back to your motivation: If you want a display function that prints a message that depends on the actual object type, the thing that is fixed is the printig, which doesn't need to be virtual. But you need a virtual function to obtain the object type. Like this:
#include <iostream>
#include <ostream>
class A {
public:
void display() { std::cout << get_message() << '\n'; }
virtual const char * get_message() { return "A instance"; }
};
class B : virtual public A {
public:
virtual const char * get_message() { return "B instance"; }
};
class C : virtual public A {
public:
virtual const char * get_message() { return "C instance"; }
};
class D : public B, public C {
public:
// virtual const char * get_message() { return B::get_message(); }
// virtual const char * get_message() { return C::get_message(); }
// virtual const char * get_message() { return "D instance"; }
};
int main(void)
{
D foo;
foo.display();
A* a_ptr = &foo;
a_ptr->display();
return 0;
}
The example as given will not compile (now this is due to the diamond pattern), because the compiler can not decide, what overrider of A::get_message(), either B::get_message() or C::get_message() should be picked in D objects, you need to make one of the comments in D real code to declare the one-and-only get_message for D, in which can re-use the existing functions.
Related
Let's say i have this simple code
#include <iostream>
using namespace std;
class A {
public:
void show() {
cout << "A" << endl;
}
};
class B {
public:
void show() {
cout << "B" << endl;
}
};
class C:public A, public B {
};
int main()
{
C obj;
obj.show();
}
this throws a compile time error because the call to function show() is ambiguous. I want to know how does the compiler understand this? Object creation is a run time process, so, how does the compiler know before hand that an object of Class C is going to be created which would invoke show(). Can anybody please tell me the concept behind this?
You are inheriting both the base classes A and B which has the same method show in C. This is the reason you are facing the compiler error ambiguous access of 'show'.
To get over it, you need to be more explicit on which `show method you would want to invoke. It would be easy to do it using the scope resolution operator.
To invoke show method of A: obj.A::show();
To invoke show method of B: obj.B::show();
This concept is called "Late Binding" in "Polymorphism". It means, the code tells the compiler to understand what to do on runtime. You should use virtual functions in this manner; and it is only available when you use this with "pointers". Let me give you a little example.
class Teacher { //base class
string name;
int numOfStudents;
public:
Teacher( const string &, int ); // constructor of base
virtual void print() const; // a virtual (polymorphic) function
};
class Principal : public Teacher{ // derived class
string SchoolName;
public:
Principal( const string &, int , const string & );
void print() const; // also virtual (polymorphic)
};
If you create a Principal object on main function and then call its print() function, compiler will run the function which is defined in "Principal" class. But if you don't define a print() function in a class which you derived from "Teacher" class, then when you call a print() function of that class' object pointer it will run the print() defined in "Teacher" class.
But again do not try this with the object itself, you should do it with pointers.
Best regards.
Here is the answer you are looking for: obj is of type C which means it is both type A and type B. I am trying to be careful not to say "has-a" when it is "is-a", but, in my mind, an object of type C has also an object of type A and type B. When you call a constructor for type C, you would also call the constructors of type A and B.
So, up to the point of creation of obj, everything is fine. But, after that the compiler has to decide which of the two show()'s to call. And that is when it is getting confused.
You are inheriting from both the classes A and B. That's why it is showing you an error, namely because it is ambiguous. To handle this you can refer explicitly to the function or method should be invoked at the time of calling by the object of the C's object. This way the compiler doesn't get confused and doesn't show any error to you.
CODE :
class A{
public:
void show(){ cout<<"Class A"; }
};
class B{
public:
void show(){ cout<<"Class B"; }
};
class C : public A , public B{
public:
void disp(){ A::show(); } // Here You can make explicit from which class the method
// shall be called. I refer to method "show" from class A.
}
main(){
C obj;
obj.disp(); // Ambiguity in Multiple Inheritance Problem Solved
}
#include <iostream>
using namespace std;
class Base1 {
public:
virtual void f(int n) = 0;
};
class Base2 {
public:
virtual void f(char *s) = 0;
};
class Derive1 : public Base1, public Base2 {
public:
void f(int n) { cout << "d1 fn" << endl; }
void f(char *s) { cout << "d1 fs" << endl; }
};
class Derive2 : public Derive1 {
public:
void f(int n) { cout << "d2 fn" << endl; }
void f(char *s) { cout << "d2 fs" << endl; }
};
int main() {
Derive1 *d1 = new Derive2();
int n = 0;
char *s = "";
d1->f(n);
d1->f(s);
return 0;
}
The above code runs as expected, but if I comment out one method of Derive1, I got conversion error; if I comment out both methods of Derive1, I got methods ambiguity error.
What confused me is that why Derive1 has to define these two methods, why defining them only in Derive2 is not working. I need some help to understand this.
Some clarifications:
Let's suppose I never want to create any instances of Derive1. So, it is totally okay if Derive1 is an abstract class.
"All pure virtual functions should have a definition in derived class." This is not true if I don't want to create instances of this derived class.
If I change f in Base1 to f1, and f in Base2 to f2(just change names), then Derive1 does not need to define any of them, just defining f1 and f2 in Derive2 works.
So, with the support of method overloading, I thought, in the above code, I declared a function with the name like f_int in Base1; in Base2 I declared a function with the name like f_str. This is the way how the compiler implements method overloading, right? But it seems like this is not the case.
Derive1 is a derived class from Base1 and Base2. Derived classes must implement all pure virtual functions of their base classes.
It doesn't help Derive1 that Derive2 implements these functions, because it is possible to instantiate a Derive1, and to do so it must implement all inherited pure virtual methods.
For example, if you did not implement the functions in Derive1, what would you expect the behavior of this to be?
Derive1* d1 = new Derive1;
int n = 0;
char *s = "";
d1->f(n);
d1->f(s);
Derive1 didn't implement these, and d1 isn't a Derive2 instance, so what is it supposed to do?
If you declare a pure virtual function in a class, it will turned to become an abstract class and you can't instantiate that one. And all pure virtual functions should have a definition in derived class. Your both base classes has pure virtual functions and so your derived1 should define the pure virtual functions of base classes.
Let's start with removing both in Derived1:
When you call d1->f, you haven't created any specific to that class, so it looks to its base classes. Each base class would be treated as a separate set of candidates. So first it checks base1 and see an f, then checks base2 and sees another f. The compiler can't pick which one to call, so the call is ambiguous. You can using the parent functions into Derived1 if you don't want to re-implement them, or give the compiler a hint about which base to use.
If you only comment out one of the functions in Derived1, the one you you leave hides both parent versions, preventing either one of them from being selected. At this point you can call the one you've defined and cannot call the other one, unless you again tell the compiler which specific base class you want to call it from.
Please refer to the following C++ code:
#include <iostream>
class A {
public:
virtual ~A() {}
virtual void display() {
std::cout << "Display A" << std::endl;
}
};
class B : public A {
// ! NO 'display()' function in this class.
};
class C : public B {
public:
void display() {
std::cout << "Display C" << std::endl;
B::display();
}
};
int main(void) {
A* ptr = new C();
ptr->display();
delete ptr;
return 0;
}
The is the output of this program:
Display C
Display A
I would expect this program to have a compilation error since B::display() is not defined.
Could somebody explain the behaviour of this code?
Thank you very much for your time!
Could somebody explain the behaviour of this code?
B simply inherits the the display function from A. Since, it's virtual B could override the behavior to be something different (i.e., if it needs a different implementation it can make one otherwise it can take what it inherits).
You're mistaking virtual functions with abstract functions. The function is virtual, insofar that it has a vtable entry that can be overwritten by subclasses of the base class. However the base class isn't required to overwrite the entry.
Case in point, the vtable entry for B::display() is A::display(), which is what you see in your example.
For completeness, you declare abstract functions in C++ like this: virtual void display() =0; with no body. This function has to be overriden for C++ to allow you to instantiate the class type, otherwise you'll get a compile error.
According to the C++ Standard (10 Derived classes)
...Unless redeclared in the derived class, members of a base class are
also considered to be members of the derived class. The base class
members are said to be inherited by the derived class. Inherited
members can be referred to in expressions in the same manner as other
members of the derived class, unless their names are hidden or
ambiguous...
So you may refer in class B inherited member function display declared in class A the same way as other members of class B.
I've read about virtual functions in C++ and understood how they provide the programmer with access to the member function of derived class using a pointer of base class. (aka Polymorphism).
The questions that have been bothering me are:
Why declare a function with a same name in the base class, if in the end it has to be declared virtual? (Note: I need answers with respect to the polymorphism aspect of virtual functions)
In the code below, if 'virtual display()' is called with a base class pointer (Line 22), it shows an error. Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
.
#include <iostream>
using namespace std;
class B
{
public:
void virtual display()
{ cout<<"Inside base class.\n"; }
};
class D : public B
{
public:
void display()
{ cout<<"Inside derived class.\n"; }
};
int main()
{
B *b;
D d;
//Line-22 b->display(); Why can't 'b' call it's own display()?
b = &d;
b->display();
system("pause");
return 0;
}
Output:
Inside derived class.
b is a pointer not an object. Initially it didn't point to anything (so indirecting through it is an error); after b = &d, it points to a D object, so using it to call a virtual function will call D's override.
The virtual dispatch mechanism is defined so that the function is chosen based on the type of the actual object that the pointer points to, not the declared type of the pointer. So if it pointed to a B object then it would call B::display; here, it points to a D object, so it calls D::display.
Why declare a function with a same name in the base class, if in the end it has to be declared virtual?
It needs to be declared in the base class so that, when using a pointer to the base class, the compiler knows that it exists. Whether calling the function through the pointer will call the base-class version, or a version overridden by a derived class, depends on the type of the object.
In the code below, if virtual display() is called with a base class pointer (Line 22), it shows an error.
That's because it doesn't point to anything, so using it is an error. If it were to point to a B object, then it would call the function declared in B.
B b_obj;
b = &b_obj;
b->display(); // "Inside base class"
Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
They're not; that's the usual way of calling them. But the pointer must point to a valid object for virtual dispatch to work.
I confess I don't quite understand your question #1. Declaring a virtual function in a base class allows derived classes to override that implementation.
There are tons of uses for this (just search for polymorphism, Liskov substitution etc.). As a simple (and contrived) example, consider this:
struct File
{
virtual void open() { some_code; }
virtual void close() { some_code; }
static std::unique_ptr<File> create();
};
struct DbgFile : File
{
virtual void open() { std::clog << "Opening"; File::open(); }
virtual void open() { std::clog << "Closing"; File::close(); }
};
std::unique_ptr<File> File::create()
{
#ifdef NDEBUG
return { new File };
#else
return { new DbgFile };
#endif
}
int main()
{
auto f = File::create();
f->open();
f->close();
}
The above main() uses the File interface, but in debug builds, it will actually work with an object of type DbgFile which logs all operations happening on it.
As to your question #2, the problem in your code is that b doesn't point anywhere. If you do this instead, it will work just fine:
int main()
{
B *b;
B bb;
D d;
b = &bb;
b->display(); // Outputs "Inside base class."
b = &d;
b->display(); // Outputs "Inside derived class."
// In addition, you can explicitly suppress dynamic dispatch:
b->B::display(); // Outputs "Inside base class."
return 0;
}
Why declare a function with a same name in the base class, if in the end it has to be declared virtual? (Note: I need answers with respect to the polymorphism aspect of virtual functions)
It's necessary because,base class has to know which function definition it needs to call at runtime. Its a kind of interface.
In the code below, if 'virtual display()' is called with a base class pointer (Line 22), it shows an error. Why are virtual functions in C++ so rigid w.r.t. not getting called by base class pointers?
Since the pointer is not initialized its throwing an error. Use like below.
Base baseObj1,*basePtr;
basePtr= &baseObj1;
basePtr->Display(); //Inside base class
I made a class with virtual function f() then in the derived class I rewrote it like the following f(int) why can't I access the base class function throw the child instance ?
class B{
public:
B(){cout<<"B const, ";}
virtual void vf2(){cout<<"b.Vf2, ";}
};
class C:public B{
public:
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
int main()
{
C c;
c.vf2();//error should be vf2(2)
}
You have to do using B::vf2 so that the function is considered during name lookup. Otherwise as soon as the compiler finds a function name that matches while traversing the inheritance tree from child -> parent -> grand parent etc etc., the traversal stops.
class C:public B{
public:
using B::vf2;
C(){cout<<"C const, ";}
void vf2(int){cout<<"c.Vf2, ";}
};
You are encountering name hiding. Here is an explanation of why it happens ?
In C++, a derived class hides any base class member of the same name. You can still access the base class member by explicitly qualifying it though:
int main()
{
C c;
c.B::vf2();
}
You were caught by name hiding.
Name hiding creeps up everywhere in C++:
int a = 0
int main(int argc, char* argv[]) {
std::string a;
for (int i = 0; i != argc; ++i) {
a += argc[i]; // okay, refers to std::string a; not int a;
a += " ";
}
}
And it also appears with Base and Derived classes.
The idea behind name hiding is robustness in the face of changes. If this didn't exist, in this particular case, then consider what would happen to:
class Base {
};
class Derived: public Base {
public:
void foo(int i) {
std::cout << i << "\n";
}
};
int main() {
Derived d;
d.foo(1.0);
}
If I were to add a foo overload to Base that were a better match (ie, taking a double directly):
void Base::foo(double i) {
sleep(i);
}
Now, instead of printing 1, this program would sleep for 1 second!
This would be crazy right ? It would mean that anytime you wish to extend a base class, you need to look at all the derived classes and make sure you don't accidentally steal some method calls from them!!
To be able to extend a base class without ruining the derived classes, name hiding comes into play.
The using directive allows you to import the methods you truly need in your derived class and the rest are safely ignored. This is a white-listing approach.
When you overload a member function in a base class with a version in the derived class the base class function is hidden. That is, you need to either explicitly qualify calls to the base class function or you need a using declaration to make the base class function visible via objects of the derived class:
struct base {
void foo();
void bar();
};
struct derived: base {
void foo(int);
using base::foo;
void bar(int);
};
int main() {
derived().foo(); // OK: using declaration was used
derived().bar(); // ERROR: the base class version is hidden
derived().base::bar(); // OK: ... but can be accessed if explicitly requested
}
The reason this is done is that it was considered confusing and/or dangerous when a member function is declared by a derived function but a potenially better match is selected from a base class (obviously, this only really applies to member functions with the same number of arguments). There is also a pitfall when the base class used to not have a certain member function: you don't want you program to suddenly call a different member function just because a member function is being added to the base class.
The main annoyance with hiding member functions from bases is when there is a set of public virtual functions and you only want to override one of them in a derived class. Although just adding the override doesn't change the interface using a pointer or a reference to the base class, the derived class can possibly not used in a natural way. The conventional work-around for this to have public, non-virtual overload which dispatch to protected virtual functions. The virtual member function in the various facets in the C++ standard library are an example of this technique.