There is a compiler issue that I am facing. The code that I want to compile is as follows
#include <iostream>
class IA
{
public:
virtual void f1() = 0;
};
class A
{
public:
virtual void f1() { std::cout << "in A::f1" <<std::endl; }
};
class IB : public IA
{
public:
virtual void f3() = 0;
};
class B : public A, public IB
{
public:
// virtual void f1() { std::cout << "in B::f1" <<std::endl; }
virtual void f3() { std::cout << "in f3" <<std::endl; }
};
int main()
{
IB* b = new B();
b->f1();
b->f3();
std::cout << "Hello, world!\n";
}
Here, If I uncomment B::f1 things workout fine. The current code gives the following compiler error.
source_file.cpp: In function ‘int main()’:
source_file.cpp:32:20: error: cannot allocate an object of abstract type ‘B’
IB* b = new B();
^
source_file.cpp:23:7: note: because the following virtual functions are pure within ‘B’:
class B : public A, public IB
^
source_file.cpp:8:18: note: virtual void IA::f1()
virtual void f1() = 0;
The intent here is that the interface, IA, would be defined in the public headers of the library. The implementation class, A, would be done in the source code. All other classes would make use of this base class(A) to implement the publicly exposed abstract interface. Is this possible?
You should change
class A
to
class A : public IA
But it's not enough, as now you get multiple instances of IA in B. So you have to make the inheritance virtual:
class A : virtual public IA {...};
class IB : virtual public IA {...};
UPDATE But is there a real reason for IB to be inherited from IA? If no, drop it, and you won't need virtual inheritance:
class A : public IA {...};
class IB {...};
int main()
{
IB* b = new B();
// b->f1(); - You can't do it now, but do you really need to?
b->f3();
return 0;
}
Related
I have an abstract interface IA, which is inherited from interfaces IB and IC with different behaviours. Also I have implementations of this interfaces B from IB and C from IC. What if I need class A implementing IA, but part of implementation it has in B and C. How to provide this.
EDITED:
Minimal, complete example:
#include <iostream>
class IB
{
public:
virtual void function_B() = 0;
};
class IC
{
public:
virtual void function_C() = 0;
};
class IA : public IB, public IC
{
};
class B : public IB
{
public:
virtual void function_B()
{
std::cout << "B\n";
}
};
class C : public IC
{
public:
virtual void function_C()
{
std::cout << "C\n";
}
};
// then I want IA implementation, but also to use
// ready implementation B and C
// this way doesn't work, the class A stays abstract
class A: public IA, public B, public C
{
};
int main()
{
IA *a = new A;
a->function_B();
a->function_C();
}
Your problem is that A inherits two times from IB, once via IA and once via B. The same is true for IC as well.
To solve this diamon problem you have to use virtual inheritance wherever a class inherits directly from IC or IB:
class IA : public virtual IB, public virtual IC
{
};
class B : public virtual IB
{
public:
virtual void function_B()
{
std::cout << "B\n";
}
};
class C : public virtual IC
{
public:
virtual void function_C()
{
std::cout << "C\n";
}
};
You need to re-implement every function of IA in A. But those can be simple forwarders.
I would also recomend aggregation over inheritance, if possible, i.e. not inherit from B and C, but make them members:
class A : public IA {
B b_;
C c_;
public:
void function_B() override { b_.b(); }
void function_C() override { c_.c(); }
};
In your code class A is inherited from class IA , class B and class C and class IA is a abstract class so you can't instantiate it.
And due to Class IA is abstract so youclass A also become abstract.
So you need to override the virtual function of class IA (i-e functions of class IB and class IC) in class A.
So you need to reimplement the above functions in class A
class A : public IA,public B,public C {
public:
void function_B() override { std::cout << "B\n";}
void function_C() override { std::cout << "C\n";}
};
I have produced a minimal example to replicate the problem I am seeing with a more complex class hierarchy structure:
#include <string>
#include <iostream>
class A
{
protected:
virtual
~A() = 0;
};
inline
A::~A() {}
class B : public A
{
public:
virtual
~B()
{
}
std::string B_str;
};
class BB : public A
{
public:
virtual
~BB()
{
}
std::string BB_str;
};
class C : public A
{
protected:
virtual
~C()
{
}
virtual
void Print() const = 0;
};
class D : public B, public BB, public C
{
public:
virtual
~D()
{
}
};
class E : public C
{
public:
void Print() const
{
std::cout << "E" << std::endl;
}
};
class F : public E, public D
{
public:
void Print_Different() const
{
std::cout << "Different to E" << std::endl;
}
};
int main()
{
F f_inst;
return 0;
}
Compiling with g++ --std=c++11 main.cpp produces the error:
error: cannot declare variable ‘f_inst’ to be of abstract type ‘F’
F f_inst;
note: because the following virtual functions are pure within ‘F’:
class F : public E, public D
^
note: virtual void C::Print() const
void Print() const = 0;
^
So the compiler thinks that Print() is pure virtual.
But, I have specified what Print() should be in class E.
So, I've misunderstood some of the rules of inheritance.
What is my misunderstanding, and how can I correct this problem?
Note: It will compile if I remove the inheritance : public D from class F.
Currently your F is derived from C in two different ways. This means that an F object has two separate C bases, and so there are two instances of C::Print().
You only override the one coming via E currently.
To solve this you must take one of the following options:
Also override the one coming via D, either by implementing D::Print() or F::Print()
Make Print non-pure
Use virtual inheritance so that there is only a single C base.
For the latter option, the syntax adjustments would be:
class E : virtual public C
and
class D : public B, public BB, virtual public C
This means that D and E will both have the same C instance as their parent, and so the override E::Print() overrides the function for all classes 'downstream' of that C.
For more information , look up "diamond inheritance problem". See also Multiple inheritance FAQ
I have produced a minimal example to replicate the problem I am seeing with a more complex class hierarchy structure:
#include <string>
#include <iostream>
class A
{
protected:
virtual
~A() = 0;
};
inline
A::~A() {}
class B : public A
{
public:
virtual
~B()
{
}
std::string B_str;
};
class BB : public A
{
public:
virtual
~BB()
{
}
std::string BB_str;
};
class C : public A
{
protected:
virtual
~C()
{
}
virtual
void Print() const = 0;
};
class D : public B, public BB, public C
{
public:
virtual
~D()
{
}
};
class E : public C
{
public:
void Print() const
{
std::cout << "E" << std::endl;
}
};
class F : public E, public D
{
public:
void Print_Different() const
{
std::cout << "Different to E" << std::endl;
}
};
int main()
{
F f_inst;
return 0;
}
Compiling with g++ --std=c++11 main.cpp produces the error:
error: cannot declare variable ‘f_inst’ to be of abstract type ‘F’
F f_inst;
note: because the following virtual functions are pure within ‘F’:
class F : public E, public D
^
note: virtual void C::Print() const
void Print() const = 0;
^
So the compiler thinks that Print() is pure virtual.
But, I have specified what Print() should be in class E.
So, I've misunderstood some of the rules of inheritance.
What is my misunderstanding, and how can I correct this problem?
Note: It will compile if I remove the inheritance : public D from class F.
Currently your F is derived from C in two different ways. This means that an F object has two separate C bases, and so there are two instances of C::Print().
You only override the one coming via E currently.
To solve this you must take one of the following options:
Also override the one coming via D, either by implementing D::Print() or F::Print()
Make Print non-pure
Use virtual inheritance so that there is only a single C base.
For the latter option, the syntax adjustments would be:
class E : virtual public C
and
class D : public B, public BB, virtual public C
This means that D and E will both have the same C instance as their parent, and so the override E::Print() overrides the function for all classes 'downstream' of that C.
For more information , look up "diamond inheritance problem". See also Multiple inheritance FAQ
Does it important in which order you inheritence abstact classes, which has same functions ?
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
class C : public A {
public:
virtual void f1() { globalF1_C(); }
};
class D : public A, public B, public C { };
class E : public A, public C, public B { };
Does D and E classes would be the same, if I would write it like below:
class D{
public:
virtual void f1() { globalF1_C(); }
virtual void f2() { globalF2_B(); }
};
class E {
public:
virtual void f1() { globalF1_B(); }
virtual void f2() { globalF2_B(); }
};
PS. I inheritence class A into class D and class E just in case I can forget make some realization of class A's function.
No there are not the same. Besides an invalid C++ code provided, we can say :
In the first case your classes D and E have two method f1() (one inherited from B and one inherited from C) and one method f2() (inherited from C). If you would be able to construct a D object name d, then d.f1() would be reported as an ambiguity that you would need to clarify either this way : d.B::f1() or this one d.C::f1().
While in the second case your classes will only have two methods f1() and f2().
#include <iostream>
using namespace std;
class A {
public:
virtual void f1() = 0;
virtual void f2() = 0;
};
class B : public A {
public:
virtual void f1() { cout << "B::f1()" << endl; }
virtual void f2() { cout << "B::f2()" << endl; }
};
class C : public A {
public:
virtual void f1() { cout << "C::f1()" << endl; }
virtual void f2() { cout << "C::f2()" << endl; }
};
class D : public B, public C { };
class E : public C, public B { };
int main() {
D d;
// d.f1(); // t.cpp:28:5: error: member 'f1' found in multiple base classes of different types
d.C::f1();
d.B::f1();
}
NO, the first version of D & E won't compile either. there would be ambiguity in resolving f1 and f2 in D and E
I have a problem that I have not yet tested/compiled and wondering if it is possible and if it is bad design?
My Problem:
I want to have an abstract base class A and a abstract derived class B.
I realize if this is possible I will have a number of pure virtual member functions in each class and also I will not be able to initialize these objects, but that is a given for abstract classes.
In my design I will have another derived class C which I would then initialize - class C would be derived from class B.
I would have something that looked like this
class C
^
|
abstract class B
^
|
abstract base class A
My Question:
Is this possible first of all? I would suspect so, but not declaring the pure virtual functions in A in class B may be troublesome?
e.x.
class A {
public:
virtual void test()=0;
};
class B: public A {
public:
virtual void test()=0;
virtual void anotherTest()=0;
};
Is the above okay?
Is this bad c++ design? In future I will have derived classes from A so it would be nice to have this design.
Nothing wrong with it, and it will certainly work. Example follows
stefanos-imac:dftb borini$ more test.cpp
#include <iostream>
class A {
public:
A(void) { std::cout << "A" << std::endl; }
virtual void method1() = 0;
};
class B : public A {
public:
B(void) : A() { std::cout << "B" << std::endl; }
virtual void method2() = 0;
};
class C : public B {
public:
C(void) : B() { std::cout << "C" << std::endl; }
virtual void method1() { std::cout << "method1" << std::endl; }
virtual void method2() {std::cout << "method2" << std::endl; }
};
int main() {
C c;
c.method1();
c.method2();
}
stefanos-imac:dftb borini$ ./a.out
A
B
C
method1
method2
Thank you for reminding me that I can still type basic C++.