Multiple Inheritance Virtual Call Ambiguity - c++

The problem at hand is hard to describe so the code is placed up front for better clarity.
struct Base
{
int b;
virtual void foo(){cout << b << endl;}
Base(int x) : b(x){}
};
struct Derived1 : Base //not virtual
{
virtual void foo(){/*Derived2's code*/}
Derived1() : Base(1){}
};
struct Derived2 : Base //not virtual
{
virtual void foo(){/*Derived2's code*/}
Derived2() : Base(2){}
};
struct MultiInheritance : Derived1, Derived2
{
void bar1()
{
//needs to access Derived1's Base foo()
}
void bar2()
{
//needs to access Derived2's Base foo()
}
};
Suppose that in some weird bizarre scenario, I would want a base class MultiInheritance that has two base classes Derived1 and Derived2 that have a common non-virtual base class Base.
There are two Base in MultiInheritance, how do I specify which Base class I wish to access in MultiInheritance?
The code above seems to work fine by casting several times, but I'm not sure if this is defined behavior or not. If it is, how is this implemented by the compiler to fulfill the needs of polymorphism? On one hand virtual calls should all result in the same virtual function table, but on the other if it does it wouldn't output different answers.
EDIT
I wish to emphasize that the Base classes are required to be non-virtual
EDIT2
Deep apologies, I seriously misrepresented myself. The code above is updated better reflects my original question.

This is known as the diamond problem.
http://www.cprogramming.com/tutorial/virtual_inheritance.html
If you want to keep base non-virtual and get the behavior you are seeking now, you can do this inside MultipleInheritance the following way to ensure you are calling the foo() function from the correct base class
struct MultiInheritance : Derived1, Derived2
{
void bar1()
{
Derived1::foo();
}
void bar2()
{
Derived2::foo();
}
};

Here's a more illustrative example.
#include <iostream>
using namespace std;
template <typename Res, typename Arg>
Res& as(Arg& arg)
{
return arg;
}
struct Base
{
virtual void foo() = 0;
};
struct Derived1 : Base {};
struct Derived2 : Base {};
struct MoreDerived1 : Derived1
{
void foo() { cout << "Derived1\n"; }
};
struct MoreDerived2 : Derived2
{
void foo() { cout << "Derived2\n"; }
};
struct MultiInheritance : MoreDerived1, MoreDerived2
{
void bar1() { as<Derived1>(*this).foo(); }
void bar2() { as<Derived2>(*this).foo(); }
};
int main ()
{
MultiInheritance m;
m.bar1();
m.bar2();
}
This example illustrates that:
You don't need to specify which Base you need explicitly using a full inheritance path, it is enough to go down to a subobject that has an unambiguous Base subobject
The virtual function mechanism works here. It would not work if you tried to call Derived1::foo().
The as helper function is just a syntactic sugar, you could just as well say
Derived1& d = *this;
d.foo();

There are two Base in MultiInheritance, how do I specify which Base
class I wish to access in MultiInheritance?
You have an ambiguity in which base-object you are calling in
void MultiInheritance::bar1(){
foo();
}
The way to resolve this is by telling the compiler where to look for foo.
void MultiInheritance::bar1(){
Derived1::foo(); // The same foo() as in your question.
}
This is what is accomplished by your
void MultiInheritance::bar1()
{
Derived1& d = *this;
This is described in the standard by §10.2.12. This is well defined. As is your chain of
void MultiInheritance::bar1()
{
Derived1& d = *this;
Base& b = *this;
by the same paragraph.
Unfortunately the scope resolution operator can't get you to jump from MultiInhteritance directly to Base as
MultiInheritance::foo(){
Derived1::Base::foo();
is describing a nested class Base.
To get to the foo() belonging to Base you use the scope resolution syntax in MultiInheritance, as well as in Derived1 and Derived2.
Derived1()::foo(){
Base::foo;
If this is inappropriate then the option you proposed is the option remaining.
If it is, how is this implemented by the compiler to fulfill the needs
of polymorphism? On one hand virtual calls should all result in the
same virtual function table, but on the other if it does it wouldn't
output different answers.
Compiler implementations differ by compiler, and as a commenter stated: Using vtables for virtual functions is an implementation detail. And if an implementation uses a vtable for virtual functions, the implementation need to take this scenario into account.

Related

Redefined virtual function call

Consider:
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo()\n"; };
};
class Derived : public Base
{
public:
void foo() override
{
std::cout << "Derived::foo()\n";
Base::foo();
}
};
int main()
{
Derived obj;
obj.foo();
return 0;
}
This is my code. Why can I call Base::foo() in the Derived class if I already redefined it in Derived class. Why doesn't the compiler delete Base::foo in class Derived after redefine?
"why compiler doesn't delete Base::foo in class Derived after redefine"
Because that isn't what virtual and override do. When you provide an override to a base class function, you do not replace it. You are defining a new version for that function. The base class's implementation continues to exist and to be accessible.
Consider the following code. Someone can still use a Base object, and the behaviour should not be changed because Derived exists. The output for base_obj.foo() should continue to be "Base::foo()" regardless of the existance of Derived. :
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo()\n"; }
};
class Derived : public Base
{
public:
void foo() override { std::cout << "Derived::foo()\n"; }
};
int main()
{
Derived obj;
obj.foo();
Base base_obj;
base_obj.foo();
return 0;
}
Also consider that multiple classes can derive from Base. I could add a class MyClass : public Base with its own version of foo(), and it should not interfere with how Base or Derived objects behave.
If overriding a member function would cause the base member function to be entirely replaced or removed, it becomes nearly impossible to reason about code without reading carefully every class that derives from it. And unless your IDE provides tools for that, it implies reading all of the code base. It would make it C++ code that uses polymorphism extremely difficult to understand.

Automatically downcast function arguments in C++

I have two classes, let's say Base and Derived:
class Base {
public:
virtual ~Base() = 0;
};
class Derived : public Base {};
and a function foo:
auto foo (Derived* d) {
...
}
Is it possible to automatically downcast its argument? So I could do something like this:
Base* b = new Derived();
foo(b);
Basically I would like to write this without explicit casting it before function call.
I read something about conversion operators/constructors but they seem not useful in my case, do you have any other idea?
Edit: Sorry, I oversimplified the question with 2 classes and just a function. But actually I've got a library of 50-ish functions and 3 classes (a superclass and 2 subclasses). This unfortunately makes the easiest and cleanest solutions unsuitable because in my opinion (correct me if I am wrong) they scale bad.
I can think of three possible solutions, depending on your needs. I've replaced raw pointers with unique_ptrs in my examples.
Case 1: You don't need the base type of each derived type to be the same.
Use CRTP to allow the base type to invoke itself as a derived type. Example implementation:
template <typename DerivedType>
class Base {
template <typename F>
auto invoke_as_derived(F&& f) {
return std::forward<F>(f)(static_cast<DerivedType*>(this));
}
};
class Derived : public Base<DerivedType> {};
Usage:
std::unique_ptr<Base<Derived>> b = std::make_unique<Derived>();
b->invoke_as_derived(foo);
Since you mentioned using a list of Base pointers, this probably won't work for you.
Case 2: You need a shared base type but only have one layer in your type hierarchy and no virtual methods.
Use std::variant and std::visit.
class Derived {};
using Base = std::variant<Derived, /* other derived types */>;
auto foo(Derived*) { ... }
class FooCaller {
operator ()(Derived& d) {
return foo(&d);
}
// Overload for each derived type.
}
Usage:
Base b = Derived();
std::visit(FooCaller{}, b);
Case 3: You need a single base type but also want virtual methods and/or additional layers in your type hierarchy.
You might try the visitor pattern. It takes some boilerplate, but it may be the best solution depending on your needs. Sketch of the implementation:
class Visitor; // Forward declare visitor.
class Base
{
public:
virtual void accept(Visitor& v) = 0;
};
class Derived : public Base
{
public:
void accept(Visitor& v) final { v.visit(*this); }
};
struct Visitor
{
virtual void visit(Derived&) = 0;
// One visit method per derived type...
};
struct FooCaller : public Visitor
{
// Store return value of call to foo in a class member.
decltype(foo(new Derived())) return_value;
virtual void visit(Derived& d)
{
return_value = foo(&d);
}
// Override other methods...
};
Usage:
std::unique_ptr<Base> b = std::make_unique<Derived>();
FooCaller foo_caller;
b->accept(foo_caller);
You could write a visitor that takes a function to apply to the element so you don't have to repeat this for all of your many functions. Alternatively, if you can alter the functions themselves, you could replace your functions with visitor types.
Edit: Simplifying the call syntax back down to foo(b)
Define an overload per function overload set to which you want to pass Base objects. Example, using the 3rd technique:
auto foo(Base* b) {
FooCaller foo_caller;
b->accept(foo_caller);
return std::move(foo_caller.return_value);
}
Now foo(b.get()) will delegate to the appropriate overload of foo at run-time.
The usual approach would not be to downcast, but to use virtual functions. I.e. put void foo() inside of the class.
#include<iostream>
class Base {
public:
virtual ~Base() = default;
virtual void foo() { std::cout << "Base foo()\n"; }
};
class Derived : public Base {
public:
void foo() override { std::cout << "Derived foo()\n"; }
};
int main()
{
Base* b = new Derived();
b->foo();
delete b;
}
outputs:
Derived foo()
If you want to make it impossible to call Base::foo(), you can set
class Base {
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
making Base an abstract class.
But if you really want to call foo(b), you can use a (templated) helper function. E.g.:
#include<iostream>
class Base {
public:
virtual ~Base() = default;
virtual void foo() = 0;
};
class Derived : public Base {
public:
void foo() override {
std::cout << "Derived foo()\n";
}
};
template<typename T>
void foo(T* t)
{
t->foo();
}
int main()
{
Base* b = new Derived();
foo(b);
delete b;
}

calling parent function on a specific function call of every child C++

So assume there is class A with function foo.
Class A is the parent of a few classes which all have the function foo.
All of the child classes need the functionality of
A::foo and adds upon it.
For example:
class A
{
public:
void foo()
{
print('A');
}
};
class B:public A
{
public:
void foo()
{
print("B");
}
};
class C:public A
{
public:
void foo()
{
print("C");
}
};
void main()
{
B b;
C c;
c.foo()// now only goes to C::foo(), meaning print C. I want it to to also go into A::foo() meaning print AC
b.foo()//now only goes to B::foo(),meaning print B. want it to print AB
}
And if I want to add class D : A with foo function it will also do A::foo() and then D::foo()
Sorry if I am missing something obvious.
EDIT : since it wasn't clear the question was if there is an automatic way to do so.
EDIT : found a workaround:
class A
{
virtual void foo2(){}
public:
void foo()
{
print('A');
foo2();
}
};
class B:public A
{
void foo2()
{
print("B");
}
public:
};
class C:public A
{
void foo2()
{
print("C");
}
public:
};
void main()
{
B b;
C c;
c.foo()// now prints AC
b.foo()//now prints AB
}
seems redundant since now there are 2 functions now.
You can call the parent class's implementation of a function using A::foo().
In your case, simply adding that function call will achieve the result you want:
class B:public A
{
public:
void foo()
{
A::foo();
print("B");
}
};
As a side note, whenever you intend to override functions, you should declare it as virtual:
class A
{
public:
virtual void foo()
{
print('A');
}
};
And then when overriding it, use the override keyword:
class B:public A
{
public:
void foo() override
{
print("B");
}
};
What you've called a workaround is an established solution to this question, and whilst some people might call it a workaround many wouldn't.
Its even got a name that covers it. The non-virtual interface pattern.
herb sutter :- http://www.gotw.ca/publications/mill18.htm
One example from S.O., there's probably more:-
Non-virtual interface design pattern in C#/C++
I'd argue that this IS a way to do it automatically.
As to your aside that its redundant because there are 2 functions - well there were 2 before (the base version and derived version).
One benefit of this approach in some designs is that if the virtual method foo2 is pure virtual (which would make A abstract) then this forces all immediate derived classes to implement foo2. (I say immediate because if B derives from A it must implement foo2 but if C then derives from B C isn't forced to implement foo2, it has access to B::foo2 )

Use multiple inheritance to satisfy abstract base class

Why exactly doesn't this work? Are the inherited function signatures subtly incorrect or is the abstract base class enforced "before" the member functions are inherited or is it something else? Could this be convinced to work without function wrappers?
#include <iostream>
struct AbsBase {
virtual void foo() = 0;
virtual void bar() = 0;
};
struct ProvideFoo {
void foo() { std::cout << "foo\n"; }
};
struct ProvideBar {
void bar() { std::cout << "bar\n"; }
};
struct Concrete : public ProvideFoo, public ProvideBar, public AbsBase {
// I guess I could put function wrappers here... sigh...
//void bar() {ProvideBar::bar();}
//void foo() {ProvideFoo::foo();}
};
int main() {
Concrete c;
c.foo();
c.bar();
}
Why your code fails to compile
I think the downvoters are a bit harsh on you, as your reasoning to supply the implementations of the two pure virtual functions through separate classes has some intuitive appeal.
Alas, you are doing two unrelated things at the same time. ProvideFoo and ProvideBar are completly unrelated to the AbsBase abstract class. You could also subclass both of them from AbsBase, but then each of them would still be an abstract class. In either case, your current Concrete is an abstract class because it derives from at least one class with a pure virtual function. You can't create objects from such classes.
Fixing your code, part I
The easiest way is to drop subclassing from AbsBase altogether and subclass from ProvideFoo and ProvideBar directly. Of course, now you don't have virtual functions inside Concrete, so further subclassing can't easily override foo and bar functionality.
#include <iostream>
struct ProvideFoo {
void foo() { std::cout << "foo\n"; }
};
struct ProvideBar {
void bar() { std::cout << "bar\n"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
Live Example I
Fixing your code, part II
You can also create multiple interfaces and multiple concrete implementations, something like this:
#include <iostream>
struct AbsFoo {
virtual void foo() = 0;
};
struct AbsBar {
virtual void bar() = 0;
};
struct ProvideFoo: AbsFoo {
void foo() { std::cout << "foo\n"; }
};
struct ProvideBar: AbsBar {
void bar() { std::cout << "bar\n"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
Live Example II
Fixing your code, part III
Now for the encore: you can also use virtual inheritance when subclassing ProvideFoo and ProvideBar from AbsBase by using the virtual keyword
#include <iostream>
struct AbsBase {
virtual void foo() = 0;
virtual void bar() = 0;
};
struct ProvideFoo: virtual AbsBase {
void foo() { std::cout << "foo\n"; }
};
struct ProvideBar: virtual AbsBase {
void bar() { std::cout << "bar\n"; }
};
struct Concrete : public ProvideFoo, public ProvideBar {};
int main() {
Concrete c;
c.foo();
c.bar();
}
This is really advanced C++ and can become really complicated if your classes also contain member data. I would prefer to use the 2nd solution for your code.
Live Example III
I didn't make this clear in the question but I really did want to know literally why the code didn't compile. TemplateRex gave an awesome answer to the question as I asked it.
That said, here's an explanation of why the code doesn't compile and but also doesn't complain about an ambiguous member name. First, here's something similar that does compile.
struct A {
virtual void foo() { std::cout << "A::foo()\n"; };
};
struct B {
void foo() { std::cout << "B::foo()\n"; }
};
struct C : public A, public B {};
int main() {
// This is fine.
C c;
// Uncommenting the next line would cause an ambiguous member name lookup and
// invalidate the program.
//c.foo();
}
Fortunately, our program is not necessarily ill-formed just because an ambiguous name lookup can occur. Our program is ill-formed if an ambiguous name lookup does occur. 10.2.7
It is possible to create a valid program with c.foo() uncommented by adding even more definitions of foo().
// Name lookup never proceeds to the base classes if it succeeds locally. 10.2.4
struct C : public A, public B {
void foo() { std::cout << "C::foo()\n"; }
};
Changing A to an abstract class by making A::foo() a pure virtual function prevents compilation.
struct A {
virtual void foo() = 0;
};
struct B {
void foo() { std::cout << "C::foo()\n"; }
};
struct C : public A, public B {};
int main() {
// This is illegal.
C c;
// The next line is irrelevant.
//c.foo();
}
The compiler error indicates that struct C is abstract. Why? Let’s start with exactly what it means to be an abstract class.
"10.4 Abstract classes
2 An abstract class is a class that can be used only as a base class of some other class; no objects of an abstract class can be created except as subobjects of a class derived from it. A class is abstract if it has at least one pure virtual function.
"
Apparently C has at least one pure virtual function and so is an abstract class and we can only inherit from it. Before getting to why C has a pure virtual function, we can already answer part of the question. C is an abstract class and we tried to create an instance, that's illegal. Simply creating the object is illegal. It doesn’t matter if you never try to access a pure virtual function.
So why does C have a pure virtual function? It must be A::foo(). What happened to B::foo()? Did A::foo() somehow take priority?
First, we usually say derived classes “have” functions they inherit but this obscures what's really going on.
"
10.1.4 [...] For each distinct occurrence of a non-virtual base class in the class lattice of the most derived class, the most derived object (1.8) shall contain a corresponding distinct base class subobject of that type. […]
"
Here it’s made clear that a derived class and base class remain distinct. We don't merely inherit a pile of functions. Now the difference between overriding a member and having access to more than one identically named members is clear. We can inherit multiple functions with identical names and signatures. We can even refer to the separate functions if we’re careful with scope but an ambiguous name lookup is illegal.
To not be an abstract class, inherited pure virtual functions must be overridden. We are indeed inheriting a pure virtual function that is not being overridden and so we have an abstract class. Incidentally we’re also inheriting a non-pure virtual function with an identical signature, but that’s just irrelevant trivia.

A way to enforce use of interface in C++

In C++, let's say I have a class Derived that implements an interface class BaseInterface, where BaseInterface has only pure virtual functions and a virtual destructor:
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
protected:
virtual void doSomething();
private:
int x;
};
No classes outside the Derived class hierarchy should call Derived::doSomething() directly, i.e., it should only be accessed polymorphically through the BaseInterface class. To enforce this rule, I have made Derived::doSomething() protected. This works well, but I'm looking for opinions pro/con regarding this approach.
Thanks!
Ken
I think you're looking for the non-virtual interface (NVI) pattern: a public non-virtual interface that calls a protected or private virtual implementation:
class BaseInterface
{
public:
virtual ~BaseInterface(){}
void doSomething() { doSomethingImpl(); }
protected:
virtual void doSomethingImpl() = 0;
};
class Derived : public BaseInterface
{
public:
Derived() {}
virtual ~Derived(){}
protected:
virtual void doSomethingImpl();
private:
int x;
};
If it is part of the interface, why would you not want users to call it? Note that as it is, they can call it: static_cast<BaseInterface&>(o).doSomething() is just an awkward way of saying o.doSomething(). What is the point of using the interface... if the object fulfills the interface, then you should be able to use it, or am I missing something?
Since you are not actually blocking anyone from calling the methods, I don't see a point in making the code more complex (both the class and users of the class) for no particular reason. Note that this is completely different from the Non-Virtual Interface in that in this idiom virtual functions are not accessible publicly (at any level) while in your case, the intention is allowing access, and making it cumbersome.
What you are doing is also mentioned in standard ISO/IEC 14882:2003(E) 11.6.1 and believe you are correct. Other than the fact, the member function isn't pure virtual in the given example. It should hold for pure virtual functions too, AFAIK.
The access rules (clause 11) for a virtual function are determined by its declaration and are not affected by the rules for a function that later overrides it.
[Example:
class B
{
public:
virtual int f();
};
class D : public B
{
private:
int f();
};
void f()
{
D d;
B* pb = &d;
D* pd = &d;
pb->f(); // OK: B::f() is public,
// D::f() is invoked
pd->f(); // error: D::f() is private
}
—end example]
Access is checked at the call point using the type of the expression used to denote the
object for which the member function is called (B* in the example above). The access of the member function in the class in which it was defined (D in the example above) is in general not known.
The key is the rest of your code. Only accept a BaseInterface* as an argument to any methods that require the doSomething() call. The client programmer is forced to derive from the interface to make his code compile.
This makes no sense to me. Regardless of which pointer you call doSomething(), you would still wind up with the method defined in most derived class. Consider the following scenario:
class BaseInterface
{
public:
virtual void doSomething() = 0;
~BaseInterface(){}
};
class Derived : public BaseInterface
{
public:
Derived() {}
~Derived(){}
virtual void doSomething(){}
private:
int x;
};
class SecondDerived : public Derived
{
public:
SecondDerived() {}
~SecondDerived(){}
private:
int x;
};
int main(int argc, char* argv[])
{
SecondDerived derived;
derived.doSomething(); //Derived::doSomething is called
BaseInterface* pInt = &derived;
pInt->doSomething(); //Derived::doSomething is called
return 0;
}