Multiple virtual inheritance ambiguity - c++

Probably best explained with an example:
struct A
{
virtual void foo() = 0;
};
struct B
{
virtual void foo() = 0;
};
struct C : A, B
{
// Implementation of A::foo
void A::foo();
// Implementation of B::foo
void B::foo();
};
// Define here; howto?
I'm aware I can define the functions inline with the class however that's not feasible in this instance (there are about 6 base classes to implement all with 40+ methods)
--
Apparently I wasn't clear enough. The question directly is: How to define both foo() methods that have been inherited without causing ambiguity issues?
The following does indeed work
void C::foo() { /* etc */ }
This will define the implementation of A::foo() yet what of B::foo() ? Bearing in mind I do not wish to define the methods within the declaration of C.
P.S., the reason for modelling the problem this way at all is predefined (COM/OLE)
--
This is fine (MSVC) albeit inline:
struct A { virtual int foo() = 0; };
struct B { virtual int foo() = 0; };
struct C : A, B
{
int A::foo() { return 1; }
int B::foo() { return 2; }
};
void main()
{
C* p = new C();
cout << ((A*) p)->foo();
cout << ((B*) p)->foo();
}

You can't provide separate overrides for two functions with the same signature defined in two base classes. (You can't define them inline within the class either, as you seem to think).
One possibility is to introduce intermediate base classes to rename the functions:
struct ABodge : A
{
void foo() {A_foo();}
virtual void A_foo() = 0;
};
struct BBodge : B
{
void foo() {B_foo();}
virtual void B_foo() = 0;
};
struct C : ABodge, BBodge
{
void A_foo();
void B_foo();
};
Alternatively, you could avoid multiple inheritance by composing two internal classes, each of which implement one of the base class interfaces:
class C
{
public:
// Could probably be defined as `operator A&()`, etc. to look more like
// inheritance, but I usually prefer conversions to be explicit.
A & asA() {return a;}
A const & asA() const {return a;}
B & asB() {return b;}
B const & asB() const {return b;}
private:
// These might need back-references to the 'C' that contains them.
struct AImpl : A {void foo();} a;
struct BImpl : B {void foo();} b;
};

Works as expected:
struct A { virtual void foo() = 0; };
struct B { virtual void foo() = 0; };
struct C : A, B { virtual void foo(); };
void C::foo() { }
For any C x;, static_cast<A&>(x).foo() and static_cast<B&>(x).foo() will call x.foo() as expected, which is precisely what the pure-virtual interfaces of A and B promise.

Related

Overload a virtual method in a derived class so it takes more parameters in C++

I have an abstract class A with the pure virtual method void foo(int a) = 0
Then I have several classes that inherit from A and all of them define the method foo. But I need one of them, B, to make it so foo takes an extra parameter, int b, so sort of an overload.
Then I would like to do this:
A *bInstance = new B();
bInstance -> foo(1, 2);
But I get an error telling me that foo is taking too many parameters.
Writing this, I realize it's kind of a weird thing to do so maybe you can't do this and it's good that you can't do it. But in case it is possible, please do tell me how I should go about it.
You can use the overloaded function of B only if the pointer to use is of type B.
See:
#include <iostream>
#include <memory>
class A{
public:
virtual void foo(int a) = 0;
};
class B : public A
{
public:
virtual void foo(int a) override
{
}
void foo(int a, int b)
{
std::cout << a << "," << b;
}
};
int main(){
auto b = std::make_shared<B>();
b->foo(1, 2);
//to use a:
A* aPtr = b.get();
aPtr->foo(1);
return 0;
}
Although Bernd's answer is a possiblility, you must ask yourself what the effect of an overload is. E.g., think of the following.
std::unique_ptr<A> bAsA = std::make_unique<B>();
bAsA->foo(1, 2); // no worky.
bAsA->foo(1); // works, but what should it do?
It there's a different interface between A and B, I would suggest to add a layer of abstraction in form of a new base class (which I will call C).
So instead of
struct A {
// common
virtual void bar() {}
// class specific
virtual void foo(int) = 0;
};
struct B: public A {
// weird unused override which is still available
void foo(int) override {}
// class specific
void foo(int, int) {}
};
use
struct C {
// common
virtual void bar() {}
};
struct A: public C {
// class specific
virtual void foo(int) = 0;
};
struct B: public C {
// class specific
void foo(int, int) {}
};
You can fully achieve want you want using a default parameter:
class A
{
public:
virtual void foo(int a, int b = 0) = 0;
virtual ~A() = default;
};
class B : public A
{
public:
void foo(int a, int b) override { }
};
class C : public A
{
public:
void foo(int a, int b = 0) override { }
};
int main()
{
A* b = new B();
A* c = new C();
b->foo(1, 2);
c->foo(1);
}
You don't have to use this parameter in C::foo implementation (and any other derived classes) if you don't need to.

Determine, at compile time, whether virtual method has been overridden

Suppose I have some class A:
// a.h:
class A {
virtual unsigned foo() {
return 0;
}
Then, I have many classes (let's call these intermediates) inheriting from A (class B, class C...etc). These classes will NEVER override foo().
// b.h:
class B : public A {
bool override_foo = true;
// ....
}
// c.h:
class C : public A {
bool override_foo = false;
}
Then, I have many classes inheriting from the intermediates. Class D, E, etc. Only one if these will ever inherit from a single intermediate, i.e, these is a 1 to 1 relationship between these classes and the intermediates. There is guaranteed to only (and always) be a single one of these classes inheriting from one of the intermediates.
Now, these classes MAY override foo. However, if they do, and the intermediate class they inherit from does not define override_foo as true, I need compilation to fail.
So, for example, if we have class D:
// d.h:
class D : public B {
unsigned foo() override();
}
Compilation would proceed fine, since B has override_foo defined as true.
However, we this should fail:
// e.h:
class E : public C {
unsigned foo() override();
}
Since C has override_foo as false.
Is this something that is achievable? Unfortunately there is very little flexibility in this problem. I work for a company where the intermediate classes, (B, C) can be changed very slightly. They are created from the compilation of a proprietary framework. I could add a member to them, or any sort of macro magic. Same for the base class A. However, the grandchildren classes, D,E, are defined by other engineers to override parts of the framework, and I need to prevent them from doing so unless the intermediate classes have some key attributes.
Thanks!
You can use final keyword to disallow inherited classes to override the method.
class A {
public:
virtual ~A() = default;
virtual void foo() {}
};
class B : public A {
public:
void foo() final { A::foo(); }
};
class C : public A {};
class D : public B {
public:
void foo() override; // <- compilation error here
};
class E : public C {
public:
void foo() override;
};
int main() {}
The other answers require your intermediate classes to override the base class version of foo() with final so the derived class can't override it instead of making a boolean member variable determine the result - and that would work. And maybe it is what you want, but it's not what you said you wanted. So I am going to answer the question you asked even though the other answers might be more what you were actually after.
If you can modify B then this makes the derived classes pretty simple to write:
#include <stdio.h>
#include <type_traits>
struct B {
virtual int foo() {
puts("B");
};
template<typename X>
using baseFooType = typename std::enable_if<X::override_foo,decltype(((B*)nullptr)->foo())>::type;
};
struct C : public B {
constexpr static bool override_foo = true;
};
struct D : public B {
constexpr static bool override_foo = true;
};
struct E : public C {
baseFooType<C> foo() override {
puts("E");
}
};
struct F : public D {
baseFooType<D> foo() override {
puts("F");
}
};
int main()
{
E().foo();
F().foo();
}
Try it here: https://onlinegdb.com/rJe5jXQhHI
If you can't modiby B then you can use a helper class like this:
#include <stdio.h>
#include <type_traits>
struct B {
virtual int foo() {
puts("B");
};
};
template<typename X>
struct baseFooType {
using type = typename std::enable_if<X::override_foo,decltype(((B*)nullptr)->foo())>::type;
};
struct C : public B {
constexpr static bool override_foo = true;
};
struct D : public B {
constexpr static bool override_foo = true;
};
struct E : public C {
baseFooType<C>::type foo() override {
puts("E");
}
};
struct F : public D {
baseFooType<D>::type foo() override {
puts("F");
}
};
int main()
{
E().foo();
F().foo();
}
Try it here: https://onlinegdb.com/BJXg4QhB8
Note: I used constexpr in the example because I thought it would need that to be passed as a template parameter but it turns out it isn't needed - you can just use const instead.
You can do everything your asking with the final keyword (c++11).
Like in other languages the final keyword prevents a method being overloaded in a derived class, or can be used to prevent a class from being derived from altoghether!
For example
class A: public X {
void foo() final; // <-- Overrides foo() in X
};
class B: public A {
void foo() override; // <-- Compile error! foo() has been declared final!
};
This works at compile time and will throw you a nice compile error :) Final also implies virtual and override (if it overrides something).

Multiple inheritance in c++ using abstract base classes [duplicate]

I tried this code:
class A
{
virtual void foo() = 0;
};
class B
{
virtual void foo() = 0;
};
class C : public A, public B
{
//virtual void A::foo(){}
//virtual void B::foo(){}
virtual void A::foo();
virtual void B::foo();
};
void C::A::foo(){}
void C::B::foo(){}
int main()
{
C c;
return 0;
}
It is OK when using the commented part, but when I try to write the definitions outside the class declaration, the compiler reports errors.
I am using the MSVC11 compiler, does anyone know how to write this?
I need to move the code into the cpp file.
Thank you~~
A function overrides a virtual function of a base class based on the name and parameter types (see below). Therefore, your class C has two virtual functions foo, one inherited from each A and B. But a function void C::foo() overrides both:
[class.virtual]/2
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides Base::vf.
As I already stated in the comments, [dcl.meaning]/1 forbids the use of a qualified-id in the declaration of a (member) function:
When the declarator-id is qualified, the declaration shall refer to a previously declared member of the class or namespace to which the qualifier refers [...]"
Therefore any virtual void X::foo(); is illegal as a declaration inside C.
The code
class C : public A, public B
{
virtual void foo();
};
is the only way AFAIK to override foo, and it will override both A::foo and B::foo. There is no way to have two different overrides for A::foo and B::foo with different behaviour other than by introducing another layer of inheritance:
#include <iostream>
struct A
{
virtual void foo() = 0;
};
struct B
{
virtual void foo() = 0;
};
struct CA : A
{
virtual void foo() { std::cout << "A" << std::endl; }
};
struct CB : B
{
virtual void foo() { std::cout << "B" << std::endl; }
};
struct C : CA, CB {};
int main() {
C c;
//c.foo(); // ambiguous
A& a = c;
a.foo();
B& b = c;
b.foo();
}
You've got just one virtual function foo:
class A {
virtual void foo() = 0;
};
class B {
virtual void foo() = 0;
};
class C : public A, public B {
virtual void foo();
};
void C::foo(){}
void C::A::foo(){}
void C::B::foo(){};
int main() {
C c;
return 0;
}
I stepped into the same problem and accidentially opened a second thread. Sorry for that. One way that worked for me was to solve it without multiple inheritance.
#include <stdio.h>
class A
{
public:
virtual void foo(void) = 0;
};
class B
{
public:
virtual void foo(void) = 0;
};
class C
{
class IA: public A
{
virtual void foo(void)
{
printf("IA::foo()\r\n");
}
};
class IB: public B
{
virtual void foo(void)
{
printf("IB::foo()\r\n");
}
};
IA m_A;
IB m_B;
public:
A* GetA(void)
{
return(&m_A);
}
B* GetB(void)
{
return(&m_B);
}
};
The trick is to define classes derived from the interfaces (A and B) as local classes (IA and IB) instead of using multiple inheritance. Furthermore this approach also opens the option to have multiple realizations of each interface if desired which would not be possible using multiple inheritance.
The local classes IA and IB can be easily given access to class C, so the implementations of both interfaces IA and IB can share data.
Access of each interface can be done as follows:
main()
{
C test;
test.GetA()->foo();
test.GetB()->foo();
}
... and there is no ambiguity regarding the foo method any more.
You can resolve this ambiguity with different function parameters.
In real-world code, such virtual functions do something, so they usually already have either:
different parameters in A and B, or
different return values in A and B that you can turn into [out] parameters for the sake of solving this inheritance problem; otherwise
you need to add some tag parameters, which the optimizer will throw away.
(In my own code I usually find myself in case (1), sometimes in (2), never so far in (3).)
Your example is case (3) and would look like this:
class A
{
public:
struct tag_a { };
virtual void foo(tag_a) = 0;
};
class B
{
public:
struct tag_b { };
virtual void foo(tag_b) = 0;
};
class C : public A, public B
{
void foo(tag_a) override;
void foo(tag_b) override;
};
A slight improvement over adigostin's solution:
#include <iostream>
struct A {
virtual void foo() = 0;
};
struct B {
virtual void foo() = 0;
};
template <class T> struct Tagger : T {
struct tag {};
void foo() final { foo({}); }
virtual void foo(tag) = 0;
};
using A2 = Tagger<A>;
using B2 = Tagger<B>;
struct C : public A2, public B2 {
void foo(A2::tag) override { std::cout << "A" << std::endl; }
void foo(B2::tag) override { std::cout << "B" << std::endl; }
};
int main() {
C c;
A* pa = &c;
B* pb = &c;
pa->foo(); // A
pb->foo(); // B
return 0;
}
Assuming that the base classes A and B are given and cannot be modified.

C++ multiple inheritance with base classes deriving from the same class

I have stumbled on a problem while trying to re-use code from different classes. I post it here in hope that some of you might be able to help me.
I have a set of classes (B,C) deriving from the same class (A) which forces the implementation of some methods (foo, run). Class B implements these method, and both B and C provide other methods:
#include<iostream>
template<class I, class O>
class A {
public:
A() {}
virtual ~A() {}
virtual void foo() const = 0; // force implementation of this function
virtual void run() const = 0; // force implementation of this function
};
template<class I, class O>
class B : public A<I,O> {
public:
B() {}
virtual ~B() {}
virtual void foo() const { // implementation for the Base class
std::cout << "B's implementation of foo" << std::endl;
}
virtual void run() const { // implementation for the Base class
std::cout << "B's implementation of run" << std::endl;
}
virtual void foobar() const { // some other function provided by this class
std::cout << "B's implementation of foobar" << std::endl;
}
};
template<class I, class O, class M>
class C : public A<I,O> {
public:
C() {}
virtual ~C() {}
virtual void bar(M m) const { // some other function provided by this class
std::cout << "C's implementation of bar with: " << m << std::endl;
}
};
Now, what I am trying to do is inherit from both B and C so that I can have the extra methods (foobar, bar), but also not have to implement the method from class A (foo) because it is already defined in B:
template<class I, class O>
class D : public B<I,O>, public C<I,O,int> {
public:
D() {}
void run() const {
this->bar(123);
this->foo();
this->foobar();
}
};
But for some reason the compiler gives me this error:
test.cpp: In function ‘int main(int, char**)’:
test.cpp:68:35: error: cannot allocate an object of abstract type ‘D<float, double>’
A<float, double> *d = new D<float, double>(); // what I need to do
test.cpp:48:11: note: because the following virtual functions are pure within ‘D<float, double>’:
class D : public B<I,O>, public C<I,O,int> {
^
test.cpp:9:22: note: void A<I, O>::foo() const [with I = float; O = double]
virtual void foo() const = 0; // force implementation of this function
This is the code I use to run it:
int main(int argc, char **argv)
{
A<float, double> *b = new B<float, double>();
b->foo(); // prints "B's implementation of foo"
b->run(); // prints "B's implementation of run"
//A<float, double> *c = new C<float, double, int>(); // obviously fails because C does not implement any of A's functions
//A<float, double> *d = new D<float, double>; // line 68: what I need to do
//d->run(); // ***throws the abstract class error
return 0;
}
I want to use the 'run' function of an object of class D from a pointer to a A. As all the functions are virtual I expect to execute implementation of each function defined in the lowest inheritance point, meaning that 'B::run' will be discarded. As 'D::run' uses functions from both B and C I need to inherit from both classes.
I hope I have described it enough and not confused anybody.
Thanks for the help!
If you change B and C to virtually inherit from the A template class, they will share a single base instance when combined by D and this error will go away:
template<class I, class O>
class B : virtual public A<I,O> {
// ...
template<class I, class O, class M>
class C : virtual public A<I,O> {
However, this pattern (known as the diamond inheritance (anti-)pattern) can be very difficult to reason about and I would strongly suggest avoiding it if possible. You are likely to run into even more obscure problems later.
Here is a sample of this technique working, but showing some results that may not be expected at first glance:
class A {
public:
virtual void foo() = 0;
};
class B : virtual public A {
public:
virtual void foo() override;
};
void B::foo()
{
std::cout << "B::foo()" << std::endl;
}
class C : virtual public A { };
class D : public B, public C { };
int main() {
D d;
C & c = d;
c.foo();
return 0;
}
Note that even though you are calling C::foo(), which is pure virtual, since there is only one A instance the inherited pure virtual function resolves to B::foo() though the shared A vtable. This is a somewhat surprising side-effect -- that you can wind up invoking methods implemented on a cousin type.
The answer by #cdhowie gives you a solution.
To understand the problem the compiler is complaining about, take a set of simpler classes:
struct A
{
virtual void foo() = 0;
};
struct B : A
{
virtual void foo() {}
}
struct C : A
{
void bar() {}
}
struct D : B, C
{
};
The class hierarchy of D is:
A A
| |
B C
\ /
D
With this inheritance structure, D has two virtual tables, one corresponding to the B inheritance hierarchy and one corresponding to C inheritance hierarchy. The difference being that in the B hierarchy, there is an implementation of A::foo() while there isn't one in the C hierarchy.
Let's say you were allowed to construct an object of type D.
D d;
C* cp = &d;
Now cp points to the C hierarchy of D, and uses a virtual table in which foo is not implemented. That will be a run time error that the compiler is helping you avoid at compile time.
I know this is a late answer but since you are deriving from a pure virtual function for class C, you have to implement it, then in those functions you call the base class:
virtual void foo() const { // for class C
B::foo();
}

C++ overload resolution problem

I've got the following structure:
struct A
{
A();
virtual ~A();
virtual void Foo() =0;
};
struct E;
struct F;
struct B: public A
{
B();
virtual ~B();
virtual void Bar(E*) =0;
virtual void Bar(F*) =0;
};
struct C: public B
{
C();
virtual ~C();
void Bar(E*);
};
struct D: public C
{
D();
virtual ~D();
void Foo();
void Bar(F*);
};
struct E: public A
{
E();
virtual ~E();
void Foo();
/* ... */
};
struct F: public A
{
F();
virtual ~F();
void Foo();
/* ... */
};
template <class _Base>
struct G: public _Base
{
G(const _Base &b)
: _Base(b)
{}
virtual ~G()
{}
using _Base::Bar; // doesn't help
/* ... */
};
When I'm trying to call Bar() on an object of type G<D> with a E*, I get the following compile-time error:
error: no matching function for call to 'G<D>::Bar(E*&)'
note: candidates are: virtual void D::Bar(F*)
If I rename the declarations of (virtual) void Bar(F*), the code compiles fine and works as expected.
Usage:
typedef std::list<E*> EList;
typedef std::list<F*> FList;
EList es;
FList fs;
G<D> player(D());
es.push_back(new E); // times many
fs.push_back(new F); // times many
for(EList::iterator i0(es.begin()), i1(es.end()); i0 != i1; ++i0)
{
player.Bar(*i0);
}
for(FList::iterator i0(fs.begin()), i1(fs.end()); i0 != i1; ++i0)
{
player.Bar(*i0);
}
1, What's wrong with multiple overloads of member functions taking different arguments?
2, Why can't the compiler tell the difference between them?
Only the versions of Bar in the most-derived class containing an override of Bar will be considered for overload resolution unless you add in using declarations. If you try
struct D: public C
{
D();
virtual ~D();
void Foo();
void Bar(F*);
using C::Bar;
};
then it should work.
From your code:
G extends D in G<D>
you call on Bar(E*) on G -> G does
not have Bar method so look into base
class
base class is D
D has Bar(F*) but no Bar(E*) -->
struct E is different type from
struct F so you get an error
To answer your question: E is not related type to F and compile can tell the difference that's why you're getting an error.
I'm not sure which Bar you add virtual but if the base class already declares Bar as virtual all the classes that extends it already have Bar virtual so it does not matter if you add the word (virtual) into extended classes.
It would help if you showed how you instantiate your object and how you call Bar(F*) on it. There are runtime decisions that depends on how you call method and what parameters you passing.