I'm using multiple inheritance in C++ and extending base methods by calling their base explicitly. Assume the following hierarchy:
Creature
/ \
Swimmer Flier
\ /
Duck
Which corresponds to
class Creature
{
public:
virtual void print()
{
std::cout << "I'm a creature" << std::endl;
}
};
class Swimmer : public virtual Creature
{
public:
void print()
{
Creature::print();
std::cout << "I can swim" << std::endl;
}
};
class Flier : public virtual Creature
{
public:
void print()
{
Creature::print();
std::cout << "I can fly" << std::endl;
}
};
class Duck : public Flier, public Swimmer
{
public:
void print()
{
Flier::print();
Swimmer::print();
std::cout << "I'm a duck" << std::endl;
}
};
Now this presents a problem - calling the duck's print method calls its respective base methods, all of which in turn call the Creature::print() method, so it ends up being called twice-
I'm a creature
I can fly
I'm a creature
I can swim
I'm a duck
I would like to find a way to make sure the base method is called only once. Something similar to the way virtual inheritance works (calling the base constructor on the first call, then only assigning a pointer to it on successive calls from other derived classes).
Is there some built-in way to do this or do we need to resort to implementing one ourselves?
If so, how would you approach this?
The question isn't specific to printing. I wondered if there's a mechanism for extending base methods and functionality while keeping the call order and avoiding the diamond problem.
I understand now that the most prominent solution would be to add helper methods, but I just wondered if there's a "cleaner" way.
Most likely this is a XY problem. But ... just don't call it twice.
#include <iostream>
class Creature
{
public:
virtual void identify()
{
std::cout << "I'm a creature" << std::endl;
}
};
class Swimmer : public virtual Creature
{
public:
virtual void identify() override
{
Creature::identify();
tell_ability();
std::cout << "I'm a swimmer\n";
}
virtual void tell_ability()
{
std::cout << "I can swim\n";
}
};
class Flier : public virtual Creature
{
public:
virtual void identify() override
{
Creature::identify();
tell_ability();
std::cout << "I'm a flier\n";
}
virtual void tell_ability()
{
std::cout << "I can fly\n";
}
};
class Duck : public Flier, public Swimmer
{
public:
virtual void tell_ability() override
{
Flier::tell_ability();
Swimmer::tell_ability();
}
virtual void identify() override
{
Creature::identify();
tell_ability();
std::cout << "I'm a duck\n";
}
};
int main()
{
Creature c;
c.identify();
std::cout << "------------------\n";
Swimmer s;
s.identify();
std::cout << "------------------\n";
Flier f;
f.identify();
std::cout << "------------------\n";
Duck d;
d.identify();
std::cout << "------------------\n";
}
Output:
I'm a creature
------------------
I'm a creature
I can swim
I'm a swimmer
------------------
I'm a creature
I can fly
I'm a flier
------------------
I'm a creature
I can fly
I can swim
I'm a duck
------------------
We can let the base class keep track of the attributes:
#include <iostream>
#include <string>
#include <vector>
using namespace std::string_literals;
class Creature
{
public:
std::string const attribute{"I'm a creature"s};
std::vector<std::string> attributes{attribute};
virtual void print()
{
for (auto& i : attributes)
std::cout << i << std::endl;
}
};
class Swimmer : public virtual Creature
{
public:
Swimmer() { attributes.push_back(attribute); }
std::string const attribute{"I can swim"s};
};
class Flier : public virtual Creature
{
public:
Flier() { attributes.push_back(attribute); }
std::string const attribute{"I can fly"s};
};
class Duck : public Flier, public Swimmer
{
public:
Duck() { attributes.push_back(attribute); }
std::string const attribute{"I'm a duck"s};
};
int main()
{
Duck d;
d.print();
}
Likewise, if it is not just printing we're after, but rather the function calls, then we could let the base class keep track of the functions:
#include <iostream>
#include <functional>
#include <vector>
class Creature
{
public:
std::vector<std::function<void()>> print_functions{[this] {Creature::print_this(); }};
virtual void print_this()
{
std::cout << "I'm a creature" << std::endl;
}
void print()
{
for (auto& f : print_functions)
f();
}
};
class Swimmer : public virtual Creature
{
public:
Swimmer() { print_functions.push_back([this] {Swimmer::print_this(); }); }
void print_this()
{
std::cout << "I can swim" << std::endl;
}
};
class Flier : public virtual Creature
{
public:
Flier() { print_functions.push_back([this] {Flier::print_this(); }); }
void print_this()
{
std::cout << "I can fly" << std::endl;
}
};
class Duck : public Flier, public Swimmer
{
public:
Duck() { print_functions.push_back([this] {Duck::print_this(); }); }
void print_this()
{
std::cout << "I'm a duck" << std::endl;
}
};
int main()
{
Duck d;
d.print();
}
An easy way is to create a bunch of helper classes that mimick the inheritance structure of your main hierarchy and do all the printing in their constructors.
struct CreaturePrinter {
CreaturePrinter() {
std::cout << "I'm a creature\n";
}
};
struct FlierPrinter: virtual CreaturePrinter ...
struct SwimmerPrinter: virtual CreaturePrinter ...
struct DuckPrinter: FlierPrinter, SwimmerPrinter ...
Then each print method in the main hierarchy just creates the corresponding helper class. No manual chaining.
For maintainability you can make each printer class nested in its corresponding main class.
Naturally in most real world cases you want to pass a reference to the main object as an argument to the constructor of its helper.
Your explicit calls to the print methods form the crux of the issue.
One way round this would be to drop the print calls, and replace them with say
void queue(std::set<std::string>& data)
and you accumulate the print messages into the set. Then it doesn't matter those functions in the hierarchy get called more than once.
You then implement the printing of the set in a single method in Creature.
If you want to preserve the order of printing, then you'd need to replace the set with another container that respects the order of insertion and rejects duplicates.
If you want that middle class method, do not call the base class method. The easiest and simplest way is to extract extra methods, and then reimplementing Print is easy.
class Creature
{
public:
virtual void print()
{
std::cout << "I'm a creature" << std::endl;
}
};
class Swimmer : public virtual Creature
{
public:
void print()
{
Creature::print();
detailPrint();
}
void detailPrint()
{
std::cout << "I can swim" << std::endl;
}
};
class Flier : public virtual Creature
{
public:
void print()
{
Creature::print();
detailPrint();
}
void detailPrint()
{
std::cout << "I can fly" << std::endl;
}
};
class Duck : public Flier, public Swimmer
{
public:
void print()
{
Creature::Print();
Flier::detailPrint();
Swimmer::detailPrint();
detailPrint();
}
void detailPrint()
{
std::cout << "I'm a duck" << std::endl;
}
};
Without details what is your actual problem is, it hard to come up with a better solution.
Use:
template<typename Base, typename Derived>
bool is_dominant_descendant(Derived * x) {
return std::abs(
std::distance(
static_cast<char*>(static_cast<void*>(x)),
static_cast<char*>(static_cast<void*>(dynamic_cast<Base*>(x)))
)
) <= sizeof(Derived);
};
class Creature
{
public:
virtual void print()
{
std::cout << "I'm a creature" << std::endl;
}
};
class Walker : public virtual Creature
{
public:
void print()
{
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can walk" << std::endl;
}
};
class Swimmer : public virtual Creature
{
public:
void print()
{
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can swim" << std::endl;
}
};
class Flier : public virtual Creature
{
public:
void print()
{
if (is_dominant_descendant<Creature>(this))
Creature::print();
std::cout << "I can fly" << std::endl;
}
};
class Duck : public Flier, public Swimmer, public Walker
{
public:
void print()
{
Walker::print();
Swimmer::print();
Flier::print();
std::cout << "I'm a duck" << std::endl;
}
};
And with Visual Studio 2015 the output is:
I'm a creature
I can walk
I can swim
I can fly
I'm a duck
But is_dominant_descendant does not have a portable definition. I wish it were a standard concept.
You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:
class Swimmer : public virtual Creature
{
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
{
std::cout << "I can swim" << std::endl;
}
};
class Flier : public virtual Creature
{
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
{
std::cout << "I can fly" << std::endl;
}
};
class Duck : public Flier, public Swimmer
{
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
{
std::cout << "I'm a duck" << std::endl;
}
};
So the answer to your question
Is there some built-in way to do this?
is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...
Related
Consider the next Example:
#include <iostream>
class Base{
public:
virtual void f() {
std::cout << "Base::f()" << std::endl;
}
};
class Derived1 : public Base
{
public:
virtual void f() override
{
Base::f();
std::cout << "Derived1::f()" << std::endl;
}
};
class Derived2 : public Base
{
public:
virtual void f() override
{
Base::f();
std::cout << "Derived2::f()" << std::endl;
}
};
class DerivedUnion : public Derived1, public Derived2
{
public:
void Derived1::f() override { // Errors
}
void Derived2::f() override { // Errors
}
};
is there some how that allow me to override the
Derived2::f()
in the
DerivedUnion{}
class?
I have tried to target specific one with namespace like style, but it didnt worked:
class DerivedUnion : public Derived1, public Derived2
// Notice DerivedUnion is not a Union, name is for
// Demostration Purposes, not intended to create
// A union Behavior
{
public:
virtual void Derived1::f() override; // Compile error
virtual void Derived2::f() override; // Compile error
virtual void f() override; // Not a compile error, but both Derived1 and Derived2 call same
};
void UseBase(Base* b){
b->f(); // expected Ambiguos call compile time
b->DerivedUnion::f() // Expected overriden DerivedUnion::f() to be called
b->Derived1::f(); // Expected overriden Derived1::f() to be called
b->Derived2::f(); // Expected overriden Derived2::f() to be called
}
An Example of it could be this one, code is self explanatory:
#include <iostream>
/* Interface Drawable */
class IDrawable {
public:
virtual void Draw() {};
};
/* Asume this is a button from one kind of bar */
class ButtonA : public IDrawable{
public:
virtual void Draw() override {
std::cout << "ButtonA::Draw()" << std::endl;
}
};
/* Asume this is a button from another kind of bar */
class ButtonB : public IDrawable{
public:
virtual void Draw() override {
std::cout << "ButtonB::Draw()" << std::endl;
}
};
/**
Where Component X is a representation that will represent 2 buttons types
*/
class ComponentX : public ButtonA, public ButtonB {
public:
void ButtonA::Draw() override { // cannot define member function ‘ButtonA::Draw’ within ‘ComponentX’
ButtonA::Draw();
std::cout << "Custom ComponentX::Draw()" << std::endl;
}
void ButtonB::Draw() override { // error: cannot define member function ‘ButtonB::Draw’ within ‘ComponentX’
ButtonB::Draw();
std::cout << "Custom ComponentX::Draw()" << std::endl;
}
};
class ComponentY : public ButtonA, public ButtonB {
public:
void ButtonA::Draw() override { // cannot define member function ‘ButtonA::Draw’ within ‘ComponentY’
ButtonA::Draw();
std::cout << "Custom ComponentY::Draw()" << std::endl;
}
void ButtonB::Draw() override { // error: cannot define member function ‘ButtonB::Draw’ within ‘ComponentY’
ButtonB::Draw();
std::cout << "Custom ComponentY::Draw()" << std::endl;
}
};
using namespace std;
void DummyAddButtonA(ButtonA* pBtnA)
{
//Add it somewhere ...
}
void DummyAddButtonB(ButtonB* pBtnB)
{
//Add it somewhere ...
}
int main()
{
ComponentX compx;
ComponentY compy;
DummyAddButtonA(&compx);
DummyAddButtonB(&compx);
DummyAddButtonA(&compy);
DummyAddButtonB(&compy);
return 0;
}
I'm familiar with polymorphism in general, but I'm fairly new to C++ in general and templates in particular. I have to following situation with a mixture of code that I cannot change (usage of a framework, all events and templated event listeners) and code under my control (clients in the example below).
#include <string>
#include <iostream>
#include <vector>
class EventBase {
public:
virtual std::string getData() const = 0;
};
class EventA : public EventBase {
public:
std::string getData() const override {
return "Event A";
}
};
class EventB : public EventBase {
public:
std::string getData() const override {
return "Event B";
}
};
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientA::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
class ClientB : public ClientBase, public IEventHandler<EventB> {
public:
void onEvent(const EventB& e) override {
std::cout << "ClientB::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
std::cout << "ClientB::onError" << std::endl;
};
void startReceiving() override {
std::cout << "ClientB::startReceiving" << std::endl;
};
};
int main(int, char**) {
//User Code
ClientA ca;
ClientB cb;
std::vector<ClientBase*> baseClients;
baseClients.push_back(&ca);
baseClients.push_back(&cb);
for(const auto client : baseClients){
client->startReceiving();
}
//Framework Code
EventA a;
EventB b;
std::vector<IEventHandler<EventA>*> eventHandlersA;
std::vector<IEventHandler<EventB>*> eventHandlersB;
eventHandlersA.push_back(&ca);
eventHandlersA[0]->onError();
eventHandlersA[0]->onEvent(a);
eventHandlersB.push_back(&cb);
eventHandlersB[0]->onError();
eventHandlersB[0]->onEvent(b);
//User Code
for(const auto client : baseClients){
client->stopReceiving();
}
}
See here: https://onlinegdb.com/2MYQhC2G5
What I want to do now is to have a common default implementation of onError.
To do so, I tried at least four approaches. Only the second worked. It would be nice to hear from C++ savants if this approach 2 is actually the way to do it.
Approach 1
Simply put onError in ClientBase and remove it from derived clients.
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Fails on compile time with
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onError' in 'ClientA'
Okay, it's abstract since it does not implement the methods needed from IEventHandler<EventA>
Approach 2
Fix the unimplemented method in ClientA but call the super class method implementation:
class ClientA : public ClientBase, public IEventHandler<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void onError() override {
ClientBase::onError();
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Works, though under the hood I think other things are happening then originally intended (might be more of a delegation then inheritance).
Maybe mess around with templates?
Approach 3: Remove the IEventHandler from the derived clients
class ClientBase : public IEventHandler<EventBase> {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const EventBase& e) = 0;
};
class ClientA : public ClientBase {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Build system hates me:
error: non-virtual member function marked 'override' hides virtual member function
note: hidden overloaded virtual function 'ClientBase::onEvent' declared here: type mismatch at 1st parameter ('const EventBase &' vs 'const EventA &')
error: variable type 'ClientA' is an abstract class
note: unimplemented pure virtual method 'onEvent' in 'ClientA' - virtual void onEvent(const EventBase& e) = 0;
Okay, so you can override methods only if the signature matches exactly.
Approach 4: Make ClientBase templated
template<class T_Event>
class ClientBase {
public:
virtual void startReceiving() = 0;
virtual void stopReceiving() {
std::cout << "ClientBase::stopReceiving" << std::endl;
}
virtual void onError(){
std::cout << "ClientBase::onError" << std::endl;
}
virtual void onEvent(const T_Event& e) = 0;
};
class ClientA : public ClientBase<EventA> {
public:
void onEvent(const EventA& e) override {
std::cout << "ClientA::onEvent - e.getData()= " << e.getData() << std::endl;
};
void startReceiving() override {
std::cout << "ClientA::startReceiving" << std::endl;
};
};
Again, no success. This time my structures to track my clients would break:
std::vector<ClientBase*> baseClients; ----> error: use of class template 'ClientBase' requires template arguments
eventHandlersA.push_back(&ca); ---> error: no matching member function for call to 'push_back'
Do you have any more ideas on how to achieve the original goal? Or is sticking to approach 2 a good solution?
Your insights into approaches 1-3 are generally correct:
Approach 1 failed because ClientBase didn't inherit from IEventHandler<> which declared the virtual method.
Approach 2 is indeed a delegation, which is fine in my opinion. Virtual methods are already a delegation - under the hood a vtable is roughly equivalent to a set of function pointers. Delegating onError is just one more level of indirection, and hopefully something called onError isn't called frequently enough to make the performance penalty significant.
Approach 3 failed because anything overriding onEvent(const EventBase& e) needs to accept any EventBase&, per the contract.
Approach 4 failed because ClientBase<EventA> and ClientBase<EventB> are completely different types that don't share a common base. Templates are more like type factories than types - there's no relationship between instantiations.
If you want to make the this work with inheritance, you can spell out that common base explicitly by having a non-template ClientBase and a template layer in between to implement onError:
template <typename TEvent>
class ErrorHandlingClient : public ClientBase, public IEventHandler<TEvent> {
public:
virtual void onError() override { /* ... */ }
};
class ClientA : public ErrorHandlingClient<EventA> {
public:
void onEvent(const EventA& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
class ClientB : public ErrorHandlingClient<EventB> {
public:
void onEvent(const EventB& e) override { /* ... */ }
void startReceiving() override { /* ... */ }
};
ClientA and ClientB will have different implemenations of onError because of the template, but they can both be casted to a common ClientBase type to store in a vector.
One last opinion - if you need an abstract class to get your desired code organization, it might be a sign that your concerns aren't separated: Maybe IEventHandler<T> should really be two interfaces, or maybe error handling should be owned by some other entity.
The basic problem is having a class template with a virtual method that does not need the template parameter. It is not wrong per se, but it can easily make one's life mighty inconvenient.
The problem with your Approach 1 is having more than one source node in the inheritance graph that has errorHandler. These functions are unrelated. Here is a simplified demo:
struct X { virtual void foo() = 0; };
struct Y { virtual void foo() {} };
struct XY : X, Y {};
XY is still abstract, despite having an implementation of foo, because there are two unrelated foos in it and the only way to unify them is to override foo in XY. This surprises a lot of people.
The best practice here (as I understand it) is moving the offending function to a common base class of X, Y and XY (create one if needed). Up the hierarchy, not down or sideways. It should be inherited virtually (not a diamond-of-death problem, since it is an ABC with no data members).
So don't do this:
template<class T_Event>
class IEventHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
virtual void onError() = 0;
};
Do this instead:
class IErrorHandler {
public:
virtual void onError() = 0;
// or whatever default implementation you want
};
template<class T_Event>
class IEventHandler : public virtual /* XXX Important! */ IErrorHandler
{
public:
virtual void onEvent(const T_Event& e) = 0;
};
class ClientBase : public virtual IErrorHandler {
virtual void onError() override {} // whatever
};
class ClientA : public ClientBase, public IEventHandler<EventA> {
virtual void onEvent(const EventA& e) {}
};
Live Demo.
Note, the MSVC compiler may issue a warning (C4250) on this. Ignore or silence it. For your convenience, here is a collection of SO posts on this topic.
I'm trying to solve an inheritance problem, where a derived class Snake inherits from LivingThing -> Animal -> Reptile, however, when I don't add virtual void crawl() to class LivingThing, the compiler says error: no member named 'crawl' in 'LivingThing'. Now I don't want to have to implement a virtual void in LivingThing which is specific for Snakes.
#include <iostream>
class LivingThing
{
public:
void breathe()
{
std::cout << "I'm breathing as a living thing." << std::endl;
}
virtual void crawl() {} //dont' want this
};
class Animal : virtual public LivingThing
{
public:
void breathe()
{
std::cout << "I'm breathing as an animal." << std::endl;
}
};
class Reptile : virtual public LivingThing
{
public:
void crawl()
{
std::cout << "I'm crawling as a reptile." << std::endl;
}
void breathe()
{
std::cout << "I'm breathing as a reptile." << std::endl;
}
};
class Snake : public Animal, public Reptile
{
public:
void breathe()
{
std::cout << "I'm breathing as a snake." << std::endl;
}
void crawl()
{
std::cout << "I'm crawling as a snake." << std::endl;
}
};
int main()
{
LivingThing *snake = new Snake();
snake->breathe();
snake->crawl();
system("pause");
return 0;
}
snake->crawl(); tries to access crawl through a LivingThing*, without a v-table reference, LivingThing* cannot call Snake::crawl.
In your current example you could just change the LivingThing pointer to be a Snake pointer.
In a more complex situation:
If you know that the pointer you're calling crawl on points to an object that is infact a Snake then you can static_cast the pointer.
if(Snake* snake = static_cast<Snake*>(livingThing))
snake->crawl();
If you have no guarantee that the living thing is actually a Snake and you have rtti available then you can use dynamic_cast.
if(Snake* snake = dynamic_cast<Snake*>(livingThing))
snake->crawl();
When you upcast object to it's base type, you can only use methods which are declared in this base class. So if you don't want to declare crawl method in your base type, you've to downcast your object before using this method:
LivingThing *creature = new Snake();
creature->breathe();
if(Snake* snake = dynamic_cast<Snake*>(creature)) snake->crawl();
I'm having trouble on my c++ code ..
class GrandParent {
public:
GrandParent()
{
printMe();
}
virtual void printMe()
{
std::cout << "GrandParent: printme" << std::endl;
}
}
class Parent : public GrandParent {
public:
Parent(){}
virtual void printMe()
{
std::cout << "Parent: printMe!" << std::endl;
}
}
class Child : public Parent {
public:
Child(){}
void printMe()
{
std::cout << "Child: printMe!" << std::endl;
}
}
int main()
{
Child *p = new Child();
delete p;
}
When I run this code, it prints "GrandParent: printMe".
my goal is to print "Child: printMe!". Is there something wrong in overriding printMe?
What you're trying to do isn't possible. At the time of GrandParent's constructor, the only part of the Child object that has been constructed and initialized is the GrandParent part - including the vtable. That is, when you call printMe(), the entry will be GrandParent's. It's only after Child gets constructed that the vtable entry for printMe() gets updated to point to Child::printMe.
Note that it's good that C++ works like this. If Child::printMe had been the one called, then you'd be calling a member function on a not-yet-constructed object. Nothing good can come of that.
Short answer: That's how C++ works.
When a virtual method is called from the constructor, not the method of the runtime class is used. Instead the method of the compile time class is used.
But there might be an escape using the Curiously Recurring Template Pattern as shown here:
#include <iostream>
template <class T>
class Base
{
protected:
Base()
{
T::printMe();
}
};
class GrandParent : Base<GrandParent>
{
public:
GrandParent()
: Base<GrandParent>()
{}
static void printMe()
{
std::cout << "GrandParent: printMe!" << std::endl;
}
};
class Parent : public GrandParent, public Base<Parent>
{
public:
Parent()
{}
static void printMe()
{
std::cout << "Parent: printMe!" << std::endl;
}
};
class Child : public Parent, public Base<Child>
{
public:
Child()
{}
static void printMe()
{
std::cout << "Child: printMe!" << std::endl;
}
};
int main()
{
GrandParent a;
std::cout << "..." << std::endl;
Parent b;
std::cout << "..." << std::endl;
Child c;
std::cout << "..." << std::endl;
}
Output:
GrandParent: printMe!
...
GrandParent: printMe!
Parent: printMe!
...
GrandParent: printMe!
Parent: printMe!
Child: printMe!
...
But yeah, then you have to deal with static methods and multiple inheritence.
Suppose I have the following hierarchy using the NVI idiom :
class Base
{
public:
virtual ~Base() {}
void foo() { cout << "Base::foo" << endl; foo_impl(); }
private:
virtual void foo_impl() = 0;
};
class A : public Base
{
private:
virtual void foo_impl() { cout << "A::foo_impl" << endl; }
};
If at some point in the hierarchy I want to "add" invariants in the non virtual base method, what would be the best way to do so ?
One way would be to recurse the NVI idiom at the SpecialBase level :
class SpecialBase : public Base
{
private:
void foo_impl() { cout << "SpecialBase::foo" << endl; bar_impl(); }
virtual void bar_impl() = 0;
};
class B : public SpecialBase
{
private:
virtual void bar_impl() { cout << "B::bar_impl" << endl; }
};
But I don't really like this idea, since I don't want to add methods (with different names) for each derived bases I add to my hierarchy...
Another way is to have the following (which is not NVI) :
class Base
{
public:
virtual ~Base() {}
virtual void foo() { base_foo(); foo_impl(); }
protected:
void base_foo() { cout << "Base::foo" << endl; }
virtual void foo_impl() = 0;
};
class SpecialBase : public Base
{
public:
virtual void foo() { base_foo(); specialbase_foo(); foo_impl(); }
protected:
void specialbase_foo() { cout << "SpecialBase::foo" << endl; }
};
class B : public SpecialBase
{
private:
virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
Which in my opinion is less confusing since at any point a concrete class just has to implement the virtual method, while a derived base class can override the base (virtual) method if it chooses too.
Is there another cleaner way to achieve the same ?
EDIT:
I'm looking for a very general design pattern that could allow me to have the following kind of hierarchy :
Base <- A
<- B
<- SpecialBase <- C
<- D
<- VerySpecialBase <- E
<- StrangeBase <- F
Where each Base class can (and will override foo), whereas classes A-F will only need to reimplement foo_impl.
Note that just adding another optional customization virtual function (e.g bar_impl) won't help here, because it only allow for one extra layer of customization, where I could possibly need an infinite number.
In my understanding, NVI is a way to prevent/discourage adding invariants to the non-virtual base method, so the fact that you want to add invariants at this point suggests that NVI either isn't the pattern you are looking for at all, or you might want to restructure your design so that you do not need to add such invariants.
That being said an alternative to simply making your previously non-virtual interface virtual would be to employ the final keyword from C++11:
class Base
{
public:
virtual ~Base() {}
virtual void foo() { base_foo(); foo_impl(); }
protected:
void base_foo() { cout << "Base::foo" << endl; }
virtual void foo_impl() = 0;
};
class SpecialBase : public Base
{
public:
virtual void foo() final // note the use of 'final'
{ base_foo(); specialbase_foo(); foo_impl(); }
protected:
void specialbase_foo() { cout << "SpecialBase::foo" << endl; }
};
class B : public SpecialBase
{
private:
virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
Here NVI is not implemented by the class Base, but is implemented at the level of SpecialBase since classes derived from SpecialBase can no longer override the public interface (namely foo).
In this way we are saying that the public interface of Base is allowed to be overridden (invariants may be added, or even the entire function may be reimplemented), but the public interface of SpecialBase is not.
Personally I find that this can be useful in some limited cases, but most of the time I simply wanted a more complete interface in Base in the first place.
Ultimately I think it is more common to use Base to clearly define what points of customization are allowed:
class Base
{
public:
virtual ~Base() {}
virtual void foo() { base_foo(); bar_impl(); foo_impl(); }
protected:
void base_foo() { cout << "Base::foo" << endl; }
virtual void bar_impl() {} // bar_impl is an optional point of customization
// by default it does nothing
virtual void foo_impl() = 0; // foo_impl is not optional derived classes
// must implement foo_impl or else they will be abstract
};
class B : public Base
{
private:
virtual void bar_impl() { cout << "SpecialBase::foo" << endl; }
virtual void foo_impl() { cout << "B::foo_impl" << endl; }
};
Note that there is no longer a need for the SpecialBase class layer at all.
This post was suggested to me as similar to something I was browsing related to NVI the other day, hence the necro.
I would suggest adding a Check-Adding mechanism in the base class, so that derived classes can add requirements. This works in a very straightforward way as long as the requirements can be tested using the base class access functions, otherwise your special MyInvariant class has to dynamic_cast the base argument of doCheckInvariantOK() for the invariant to work.
edit: I understand 'invariant' to be along the lines of pre- and post-conditions of foo(), as in formal verfication. If you want to add functionality before and/or after base_foo(), what I think you're actually after, you can do it in an analogous fashion.
class Base
{
public:
virtual ~Base() {}
void foo()
{
cout << "Base::foo" << endl;
//Can use invariants as pre and/or postconditions for foo_impl
for(const std::unique_ptr<InvariantBase>& pInvariant : m_invariants)
{
//TODO cout << "Checking precondition " << pInvariant->GetDescription() << endl;
if(!pInvariant->CheckInvariantOK(*this))
{
//Error handling
}
}
foo_impl();
}
protected:
void AddInvariant(std::unique_ptr<InvariantBase>&& pInvariant)
{
m_invariants.push_back(std::move(pInvariant));
}
struct InvariantBase
{
bool CheckInvariantOK(const Base& base)
{
return doCheckInvariantOK(base);
}
private:
virtual bool doCheckInvariantOK(const Base& base) = 0;
};
private:
std::list<std::unique_ptr<InvariantBase>> m_invariants;
virtual void foo_impl() = 0;
};
class A : public Base
{
private:
virtual void foo_impl() { cout << "A::foo_impl" << endl; }
};
class SpecialBase : public Base
{
public:
SpecialBase()
: Base()
{
AddInvariant(std::unique_ptr<MyInvariant>(new MyInvariant() ) );
}
private:
void foo_impl() { cout << "SpecialBase::foo" << endl; bar_impl(); }
virtual void bar_impl() = 0;
struct MyInvariant : public InvariantBase
{
virtual bool doCheckInvariantOK(const Base& base) override
{
//TODO: special invariant code
}
};
};
class B : public SpecialBase
{
private:
virtual void bar_impl() { cout << "B::bar_impl" << endl; }
};