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.
Related
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.
The following code illustrates my question:
namespace foo1
{
class bar1
{
public:
virtual void fn() = 0; //this must remain pure virtual
};
};
namespace foo2
{
class bar2
{
public:
virtual void fn() = 0; //this must remain pure virtual
};
};
class bar3: public foo1::bar1, public foo2::bar2
{
public:
//can i separately override virtual functions from inherited
//classes that have the same name?
void foo1::bar1::fn() override {std::cout << "bar1";} //error
void foo2::bar2::fn() override {std::cout << "bar2";} //error
};
int main()
{
bar3* obj = new bar3();
((foo1::bar1*)obj)->fn(); //i want this to print "bar1"
((foo2::bar2*)obj)->fn(); //and this to print "bar2"
}
Basically I want to be able to override inherited functions, such that by simply casting my base class object to one of the inherited classes, I can call the different functions even though they have the same name. Is this possible?
Sure.
struct foo1bar1helper:public foo1::bar1{
void fn()final{foo1bar1fn();}
virtual void foo1bar1fn()=0;
};
now bar3 just inherits from this instead of bar1 and overrides foo1bar1fn(),
Do the same with bar2.
You can also use CRTP to dispatch and do away with the extra vtable lookup;
template<class D>
struct foo1bar1helper:public foo1::bar1{
void fn()final{static_cast<D*>(this)->foo1bar1fn();}
};
template<class D>
struct foo2bar2helper:public foo2::bar2{
void fn()final{static_cast<D*>(this)->foo2bar2fn();}
};
class bar3:
public foo1bar1helper<bar3>,
public foo2bar2helper<bar3>
{
public:
void foo1bar1fn(){}
void foo2bar2fn(){}
};
You can not do that. When you do foo1::bar1::fn(), compiler thinks that you are defining function fn of 'bar1' of 'foo1' namespace in class bar3. Hence compiler is throwing below error.
error: cannot define member function ‘foo1::bar1::fn’ within ‘bar3’
But when you extend from an abstract class, you need to give the definition of the function (which should be part of your derived class) in derived class.
Can I have a virtual function in the base class and some of my derived classes do have that function and some don't have.
class A{
virtual void Dosomething();
};
class B : public A{
void Dosomething();
};
class C : public A{
//Does not have Dosomething() function.
};
From one of my c++ textbook:
Once a function is declared virtual, it remains virtual all the way down the inheritance, even if the function is not explicitly declared virtual when the derived class overrides it.
When the derived class chooses not to override it, it simply inherits its base class's virtual function.
Therefore to your question the answer is No. Class c will use Class A's virtual function.
Derived classes do not have to implement all the virtual functions, unless it is a pure virtual function. Even in this case, it will cause an error only when you try to instantiate the derived class( without implementing the pure virtual function ).
#include <iostream>
class A{
public :
virtual void foo() = 0;
};
class B: public A{
public :
void foo(){ std::cout << "foo" << std::endl;}
};
class C: public A{
void bar();
};
int main() {
//C temp; The compiler will complain only if this is initialized without
// implementing foo in the derived class C
return 0;
}
I think the closest you might get, is to change the access modifier in the derived class, as depicted below.
But, I would consider it bad practice, as it violates Liskov's substitution principle.
If you have a situation like this, you might need to reconsider your class design.
#include <iostream>
class A {
public:
virtual void doSomething() { std::cout << "A" << std::endl; }
};
class B : public A {
public:
void doSomething() override { std::cout << "B" << std::endl; };
};
class C : public A {
private:
void doSomething() override { std::cout << "C" << std::endl; };
};
int main(int argc, char **args) {
A a;
a.doSomething();
B b;
b.doSomething();
C c;
//c.doSomething(); // Not part of the public interface. Violates Liskov's substitution principle.
A* c2 = &c;
c2->doSomething(); // Still possible, even though it is private! But, C::doSomething() is called!
return 0;
}
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.
I've read in a book Stephen Prata - "C++ Primer Plus VI Edition" that in an abstract class I can write a definition of pure method. I understood that I can write for example void pure() = 0 and then I can make a definition of that method in this class. I thought that = 0 is only to make the class abstract and if I make another class inheriting from that class I don't have to overwrite it (I don't know if word "overwrite" is right, I meant that I wan't to hide the method from the basic class by writing a method with the same name in secondary class).
I checked it in compiler and I get warning that "it has no overrider". So if I have to overwrite this pure virtual method (with definition in abstract class) in secondary class how can I use this definition from basic class? Is it useless?
Are you looking for something like this:
class Abstract {
public:
virtual void f() = 0;
};
// A pure virtual function can still be defined.
// It has to be defined out-of-class.
void Abstract::f() {
// Do something
}
class Concrete : public Abstract {
public:
void f() {
Abstract::f(); // call base class implementation
// Do something more
}
};
Here is an example that explains the notion of pure functions
#include <iostream>
struct A
{
virtual ~A() = default;
virtual void what() const = 0;
};
void A::what() const
{
std::cout << "struct A";
}
struct B : A
{
virtual void what() const = 0;
};
void B::what() const
{
A::what();
std::cout << ", struct B : A";
}
struct C : B
{
void what() const;
};
void C::what() const
{
B::what();
std::cout << ", struct C: B";
}
int main()
{
// A a; compiler error
// B b; compiler error
C c;
const A &rc = c;
rc.what();
std::cout << std::endl;
return 0;
}
The program output is
struct A, struct B : A, struct C: B
In this example classes A and B are abstract because they have a pure virtual function though each of them provides the corresponding definition of their pure virtual function.
And only class C is not abstract because it redeclares the virtual function as a non-pure virtual function.
If you want to instantiate the inherited class, i.e. to create an object of this type, you must have all pure virtual methods implemented in the inherited class.
In other words, the pure virtual methods not only define the class interface but also force you to provide their actual implementation.