there's this code :
class Base{
public:
void disp(){
cout<<"base"<<endl;
}
};
class Der1:public Base{
public:
void test1(){
cout<<"der1 test1"<<endl;
}
};
class Der2:public Base{
public:
void test2(){
cout<<"der2 test2"<<endl;
}
};
class Der3:public Der1,Der2{
public:
void fun(){
cout<<"Der3 fun"<<endl;
}
};
int main()
{
Der3 d;
d.test1();
}
OUTPUT: der1 test1 //printed successfully
but for
int main()
{
Der3 d;
d.test2();
}
it gives error that Der2 is inaccessible ...
However when i change the code to
class Base{
public:
void disp(){
cout<<"base"<<endl;
}
};
class Der1:public Base{
public:
void test1(){
cout<<"der1 test1"<<endl;
}
};
class Der2:public Base{
public:
void test2(){
cout<<"der2 test2"<<endl;
}
};
class Der3:public Der2,Der1{ //***changed the order here***
public:
void fun(){
cout<<"Der3 fun"<<endl;
}
};
int main()
{
Der3 d;
d.test2();
}
it outputs: der2 Test2
Can someone explain what is happening here ?
It should be:
class Der3:public Der2, public Der1{
If you don't specify the access qualifier, it defaults to private.
Also because you have a common base in the two types inherited in Der3 you should use virtual inheritance in Der1 and Der2. This avoids replicating the common Base members (if any.)
class Der1:public virtual Base{...
class Der2:public virtual Base{...
You have to add the accessibility to each base class:
class Der3:public Der1, public Der2{
public:
void fun(){
cout<<"Der3 fun"<<endl;
}
};
When you switch the order Der2 is a public base but Der1 is private.
class Der3:public Der1,Der2 {
The 'public' there is only good for the next base class. You want to write:
class Der3: public Der1, public Der2 {
Also, it should be noted that this example also shows the deadly "diamond" inherience pattern, so it's designer clearly should be slapped.
By default, class inheritance is private. And so:
class Der3: public Der1, Der2
is the same as:
class Der3: public Der1, private Der2
You need to use public inheritance for both base classes:
class Der3: public Der1, public Der2
Related
I have a naive C++ inheritance class question. I have one base class Base, two derived classes DerivedA and DerivedB and two other distinct classes A and B which share the names of some methods.
Ideally I would like to design methods in the base class that use the methods of A and B. My attempt is the following
#include <cstdio>
class A{
public :
A(){};
void speak(){printf("hello A\n");};
};
class B{
public :
B(){};
void speak(){printf("hello B\n");};
};
class Base{
public:
Base(){};
void method(){property.speak();}
A property;
};
class DerivedA : public Base{
public:
using Base::Base;
A property;
};
class DerivedB : public Base{
public:
using Base::Base;
B property;
};
int main(int argc, char *argv[]){
DerivedA da;
DerivedB db;
da.property.speak();
db.property.speak();
// Attempting to call the shared method on the two distinct properties
da.method();
db.method();
}
Could you point me to a better design ? I suspect I should use templates but I am not sure how.
There are several options with different advantages and disadvantages.
You can make the base class a template like this:
template<class Property>
class Base{
public:
Base(){};
void method(){property.speak();}
Property property;
};
class DerivedA : public Base<A>{
};
class DerivedB : public Base<B>{
};
It is clear and simple, but notice that DerivedA and DerivedB in this case have no common base class, so you can't, e.g. put pointers to them in the same container.
You can use polymorphism.
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;
};
class DerivedA : public Base{
public:
A property;
void method() override { property.speak(); }
};
class DerivedB : public Base{
public:
B property;
void method() override { property.speak(); }
};
This is a bit more complex, involves some code duplication and requires more resources (to store virtual table e.g.), but now the classes really have a common ancestor.
Combine templates and polymorphism
class Base{
public:
virtual ~Base() {}
virtual void method() = 0;
};
template<class Property>
class Derived: public Base {
public:
Property property;
void method() override { property.speak(); }
};
using DerivedA = Derived<A>;
using DerivedB = Derived<B>;
This is actually option #2, but with no code duplication: we make the compiler generate code for us using templates.
Other options. There may be other more specialized options depending on your requirements.
Question
Why not to try virtual inheritance if it seems to solve my diamond inheritance problem below?
Briefing:
While learning C++, I came with some compiler errors for the following code:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
void Hello()
{
printf("Hello");
}
};
class IBar : public IFoo{
public:
virtual void HelloWorld() = 0;
};
class Bar : public IBar, public Foo{
public:
void HelloWorld()
{
Hello();
printf("World");
}
};
int main()
{
Bar b;
b.HelloWorld();
system("pause");
return 0;
}
I want Bar to implement abstract class IBar which has IFoo as a base class but then I want all the implementation of IFoo provided by Bar's second base class Foo.
I get 2 compiler errors (GCC 4.9.2): One related to ambiguities and another one about missing implementations for abstract class IFoo.
Then I found this question and got to meet the concept of virtual inheritance, which lead me to this page. Following the tutorial, I added virtual inheritance and all problems were gone:
class Foo : public virtual IFoo{...
class IBar : public virtual IFoo{...
But a user in the question suggest not to try virtual inheritance. Hence my question.
Your class
Bar
must override
Hello
otherwise class Bar also becomes purely abstract, because
Hello
is inherited all the way from
IFoo.
Whenever a class inherits an abtract base class it must implement all of the base class' pure virtual functions, otherwise the derived class itself also becomes abstract.
class Base{
public:
virtual void foo() = 0;
};
// this class is abstract, it doesn't implement Base::foo
class Derived1 : public Base{
public:
void fooDerived() {}
};
// this class is not abstract, it implements Base::foo
class Derived2 : public Base{
public:
void foo() {}
};
As suggested in another answer, in C++11 you can declare the function using the override keyword, which ensures that the function overrides a virtual function. Like this:
// this class is not abstract, it implements Base::foo
class Derived2 : public Base{
public:
void foo() override {}
};
Virtual inheritance solves another problem, the problem of ambiguity when inheriting from more than one base class which declares identical functions or members.
Your Hello() call in Bar::HelloWorld() is ambiguous. The compiler can't tell if you are trying to call Hello() from IBar or Foo. You can call Foo::Hello() or IBar::Hello() in it's place. That being said, your inheritance structure doesn't really make sense.
Your Bar class also needs to override Hello that it inherits from IBar.
If you have c++11, it would be a good idea to mark the virtual functions you are overriding with the override keyword:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
virtual void Hello() override
{
printf("Hello");
}
};
class IBar : public IFoo{
public:
virtual void HelloWorld() = 0;
};
class Bar : public IBar, public Foo{
public:
virtual void HelloWorld() override
{
Foo::Hello();
printf("World");
}
void Hello() override {}
};
int main()
{
Bar b;
b.HelloWorld();
system("pause");
return 0;
}
To answer your question on virtual inheritance, you could easily change your inheritance structure to something that still works that avoids a diamond pattern. The diamond pattern is rarely needed and is usually avoidable:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
virtual void Hello() override
{
printf("Hello");
}
};
class IBar {
public:
virtual void World() = 0;
};
class Bar : public IBar{
public:
virtual void World() override
{
printf("World");
}
};
class FooBar : public Foo, public Bar
{
public:
virtual void HelloWorld()
{
Hello();
World();
}
};
int main()
{
FooBar b;
b.HelloWorld();
system("pause");
return 0;
}
Let's say the scenario is this.
IBase - interface.
BaseImpl - implementation.
BaseStub - allocates std::unique_ptr to BaseImpl named m_impl.
And then how to achieve the following?
IDerived - interface.
DerivedImpl - implementation, inherits from BaseImpl.
DerivedStub - allocates std::unique_ptr to DerivedImpl named m_impl, inherits from BaseStub.
It becomes a problem that BaseStub already allocates its implementation, and since DerivedStub does the same, it conflicts.
class IBase
{
public:
virtual void f1() = 0;
};
class IDerived
{
public:
virtual void f2() = 0;
};
class BaseImpl : public IBase
{
public:
virtual void f1() override {}
};
class DerivedImpl : public BaseImpl, public IDerived
{
public:
virtual void f2() override {}
};
class BaseStub : public IBase
{
public:
BaseStub() { m_impl.reset(new BaseImpl()); }
virtual void f1() override { m_impl->f1(); }
private:
std::unique_ptr<BaseImpl> m_impl;
};
// But this also creates BaseStub::m_impl.
class DerivedStub : public BaseStub, public IDerived
{
public:
DerivedStub() { m_impl.reset(new DerivedImpl()); }
virtual void f2() override { m_impl->f2(); }
private:
std::unique_ptr<DerivedImpl> m_impl;
};
when does ambiguity arise in multiple inheritance?
When you have replicated base class in several paths of inheritance and you are trying to cast to it or call its member-function.
struct A { };
struct B : A { };
struct C : A { };
struct D : B, C { }; // has replicated A as the base class
D d;
A* a = static_cast<A*>(&d); // oops
The problem has several remedies which depend on the context heavily (using virtual base classes, just refine the aforementioned cast, etc.)
More info here, especially here.
One famous example of ambiguity in multiple inheritance is the so-called Diamond Problem.
Summary:
"In object-oriented programming languages with multiple inheritance and knowledge organization, the diamond problem is an ambiguity that arises when two classes B and C inherit from A, and class D inherits from both B and C. If a method in D calls a method defined in A (and does not override the method), and B and C have overridden that method differently, then from which class does it inherit: B, or C?"
You can find details here: Wikipedia: Diamond Problem
struct Base{
void foo(){
}
};
struct Derived1 : public Base{
};
struct Derived2 : public Base{
};
struct Final : public Derived1, public Derived2{
};
int main(){
Final f;
f.foo();
}
See on Ideone. To fix, simply use virtual inheritance:
struct Derived1 : virtual public Base{
};
struct Derived2 : virtual public Base{
};
Another possibility for ambigouty is the following:
struct Base1{
void foo(){
}
};
struct Base2{
void foo(){
}
};
struct Final : public Base1, public Base2{
};
int main(){
Final f;
f.foo();
}
Again, on Ideone. To fix, simple make do the following in Final:
struct Final : public Base1, public Base2{
using Base1::foo;
// or
// using Base2::foo;
};
When it makes names used unclear
class baseX
{
private:
void* callA();//will never be ambiguous.
protected:
void* callB();
public:
void* callC();
}
class baseY
{
private:
void* callA();//will never be ambiguous.
protected:
void* callB();
public:
void* callC();
}
class derived: public baseX, public baseY
{
void someMethod()
{
void* x = baseX::callB();//not ambiguous
void* y = baseY::callB();//not ambiguous
void* z = callB();//ambiguose
}
}
void someFunction(derived& d)
{
void* x = d.CallC();//ambiguous
}
Ambiguity can also happen when the same class is the base through more than one route:
class Base
{
public void call();
}
class DerivedX : public Base
{
}
class DerivedY : public Base
{
}
class GrandChild : public DerivedX, public DerivedY //What does call() do?
{
}
This can be solved with virtual bases:
class Base
{
public void call();
}
class DerivedX : public virtual Base
{
}
class DerivedY : public virtual Base
{
}
class GrandChild : public DerivedX, public DerivedY //only one "Base" class in inheritance, shared between DerivedX and DerivedY
{
}
I am curious if there is a neat way to expose methods in the base class of a derived interface.
So in code: -
class cbase {
public:
void MyMethodA() { }
};
class cderived : public cbase {
public:
void MyMethodB() { }
}
class ibase {
public:
virtual void MyMethodA() = 0;
};
class iderived : public ibase {
public:
virtual void MyMethodB() = 0;
};
Now if I make cbase inherit ibase, and cderived implement iderived, the compiler will complain that when I instantiate cderived, MyMethodA() is abstract and not implemented.
MyMethodA() is implemented in the base class and through ibase. Is the only way to fix this to reimplement ibase's methods in the cderived class? If so, yuck!
So as below: -
class cbase : public ibase {
public:
void MyMethodA() { }
};
class cderived : public cbase, public iderived {
public:
void MyMethodA() { cbase::MyMethodA(); }
void MyMethodB() { }
};
cderived inst;
iderived *der = &inst;
der->MyMethodA();
der->MyMethodB();
ibase *bas = der;
bas->MyMethodA();
I hope this is enough to convey the question. :) It might sound a little loopy as we are trying to refactor old code.
I am sure there is plenty of eager commentary out there ;)
If I understand correctly you want to make ibase a virtual base class of iderived and cbase.
This was there is only one instance of each of your interface classes in the class hierarchy and when you join cbase and iderived together at the cderived level the non-virtual override of MyMethodA in cbase is used because it is the dominating override.
See here: Hidden Features of C++?
E.g.
class ibase {
public:
virtual void MyMethodA() = 0;
};
class iderived : public virtual ibase {
public:
virtual void MyMethodB() = 0;
};
class cbase : public virtual ibase {
public:
void MyMethodA() { }
};
class cderived : public cbase, public virtual iderived {
public:
void MyMethodB() { }
};
int main()
{
cderived inst;
iderived *der = &inst;
der->MyMethodA();
der->MyMethodB();
ibase *bas = der;
bas->MyMethodA();
}
Take a look into multiple inheritance.
The answer to that faq item is basically answer to your question :
class cderived : public virtual cbase {
public:
void MyMethodB() { }
}
class ibase {
public:
virtual void MyMethodA() = 0;
};
class iderived : public virtual ibase {
public:
virtual void MyMethodB() = 0;
};