Please help me solve this problem. WhiteDragon is to call Dragon::attacks() instead of
MonsterImplement::attacks(), and there is ambiguity error here. If I change Dragon to
be derived from MonsterImplement, then the line
std::cout << monster->numAttacks << std::endl; won't compile because Dragon has no numAttacks data member (nor should it, because different types of Dragons are to have different values). So I need WhiteDragon to call Dragon::attacks() and to call finalizeMonster() during its instantiation. If I make Dragon virtual derived class of Monster, WhiteDragon calls up MonsterImplement::attacks() instead.
#include <iostream>
struct Monster {
virtual void finalizeMonster() {}
virtual void attack() {}
};
template <class MONSTER, int NUM>
struct MonsterInt: virtual public Monster {
static int numAttacks;
};
template <class MONSTER, int NUM>
int MonsterInt<MONSTER, NUM>::numAttacks = NUM;
template <class BASE, class MONSTER>
struct MonsterImplement: virtual public BASE {
MonsterImplement() {finalizeMonster();}
virtual void finalizeMonster() override;
virtual void attack() override {std::cout << "MonsterImplement::attack()" << std::endl;}
};
struct Dragon: public Monster { // or Dragon: public MonsterImplement<Monster, Dragon> ?
// but then Dragon will also call the MonsterImplement constructor (when it has no numAttacks member)
virtual void attack() override {std::cout << "Dragon::attack()" << std::endl;}
};
struct WhiteDragon: public MonsterInt<WhiteDragon, 3>,
public MonsterImplement<Dragon, WhiteDragon> {
WhiteDragon(): MonsterImplement<Dragon, WhiteDragon>() {}
};
template <class BASE, class MONSTER>
inline void MonsterImplement<BASE, MONSTER>::finalizeMonster() {
MONSTER* monster = static_cast<MONSTER*> (this);
std::cout << monster->numAttacks << std::endl;
}
int main() {
WhiteDragon wd;
wd.attack();
}
(Copied from an earlier comment.)
Perspective #1
CRTP is meant to provide non-dynamic behavior. If the value of "numAttacks" vary with each derived class, this is not a "non-dynamic" situation. A counter-example would be to put a non-static non-virtual method int numAttacks() { return 3; } in a derived class, and then in the CRTP base class add some methods (the attack logic that is shared across all derived classes), which can then call the numAttacks() method on its derived class, without incurring a virtual function call.
Example:
struct Monster
{
virtual void attack() = 0;
virtual int getNumAttacks() const = 0;
};
template <struct MONSTER>
struct AttackLogic : virtual public Monster
{
virtual void attack() override
{
/* allowed to call MONSTER::getNumAttacks(), renamed to avoid confusion. */
int numAttacks = static_cast<MONSTER*>(this).getNumAttacks();
/* Use the value in attack calculations. */
}
};
struct Unicorn
: virtual public Monster
, virtual public AttackLogic<Unicorn>
{
virtual int getNumAttacks() const override
{
return 42; // Unicorn is awesome
}
};
Disclaimer: Code only meant to explain my suggestion. Not intended for practical use. Not tested with compiler. My knowledge of virutal inheritance is weak, so there may be mistakes or broken guidelines in the sample code above.
Your current inheritance chain is: (base at top)
Monster
Dragon
MonsterImplement<Dragon, WhiteDragon>
WhiteDragon
Monster defines:
virtual finalizeMonster() // abstract
virtual attack() // abstract
Dragon defines:
virtual attack() // concrete, overrides Monster.attack()
MonsterImplement<...> defines:
virtual attack() // concrete, overrides Dragon.attack() and Monster.attack()
WhiteDragon defines:
(no new virtual methods defined)
It is very clear that "after fixing the bug", that MonsterImplement.attack() will be called, because it is a subclass of Dragon and therefore overrides it.
In general it only says that the current inheritance hierarchy is badly designed, and that nobody would be able to fix it.
Perspective #2
Injecting a static int through CRTP pattern is rarely worth the effort. CRTP is more suitable for injecting a set of non-static, non-virtual methods ("boilerplate") in a way that will not be overridden, that saves every derived class from re-implementing the same "boilerplate".
At the minimum, convert the static int numAttacks into a virtual function
virtual int numAttacks() const { throw std::exception(); }
or
virtual int numAttacks() const = 0; // abstract
and then provide a concrete implementation in WhiteDragon to return 3.
struct WhiteDragon : ...
{ ...
virtual int numAttacks() const override { return 3; }
...
};
template <class MONSTER, int NUM>
struct MonsterInt: virtual public Monster {
static int numAttacks;
};
What's the purpose of this class? It seems like all it does is give a class a number of attacks, in which case it doesn't really make sense to derive from monster.
template <int NUM>
struct MonsterInt {
static int numAttacks;
};
That 'fixes' the program I think, but it's hard to really say because intention is hard to derive from your code.
Related
Given a base class which has some virtual functions, can anyone think of a way to force a derived class to override exactly one of a set of virtual functions, at compile time? Or an alternative formulation of a class hierarchy that achieves the same thing?
In code:
struct Base
{
// Some imaginary syntax to indicate the following are a "pure override set"
// [
virtual void function1(int) = 0;
virtual void function2(float) = 0;
// ...
// ]
};
struct Derived1 : Base {}; // ERROR not implemented
struct Derived2 : Base { void function1(int) override; }; // OK
struct Derived3 : Base { void function2(float) override; }; // OK
struct Derived4 : Base // ERROR too many implemented
{
void function1(int) override;
void function2(float) override;
};
I'm not sure I really have an actual use case for this, but it occurred to me as I was implementing something that loosely follows this pattern and thought it was an interesting question to ponder, if nothing else.
No, but you can fake it.
Base has non-virtual float and int methods that forward to a pure virtual std variant one.
Two helper classes, one int one float, implement the std variant one, forwarding both cases to either a pure virtual int or float implementation.
It is in charge of dealing with the 'wrong type' case.
Derived inherit from one or another helper, and implement only int or float.
struct Base
{
void function1(int x) { vfunction(x); }
void function2(float x) { vfunction(x); }
virtual void vfunction(std::variant<int,float>) = 0;
};
struct Helper1:Base {
void vfunction(std::variant<int,float> v) final {
if (std::holds_alternative<int>(v))
function1_impl( std::get<int>(v) );
}
virtual void function1_impl(int x) = 0;
};
struct Helper2:Base {
void vfunction(std::variant<int,float> v) final {
if (std::holds_alternative<float>(v))
function2_impl( std::get<float>(v) );
}
virtual void function2_impl(float x) = 0;
};
struct Derived1 : Base {}; // ERROR not implemented
struct Derived2 : Helper1 { void function1_impl(int) override; }; // OK
struct Derived3 : Helper2 { void function2_impl(float) override; }; // OK
This uses https://en.wikipedia.org/wiki/Non-virtual_interface_pattern -- the interface contains non-virtual methods, whose details can be overridden to make them behave differently.
If you are afraid people will override vfunction you can use the private lock technique, and/or just give it a name like private_implementation_detail_do_not_implement and trust your code review process.
Or an alternative formulation of a class hierarchy that achieves the same thing?
One option is to have an intermediate base class that implements one function.
struct Base
{
virtual ~Base() {};
virtual void function(int) = 0;
virtual void function(float) = 0;
};
template <typename T>
struct TBase : Base
{
virtual void function(T) override {}
};
struct Derived1 : Base {};
struct Derived2 : TBase<float> { void function(int) override {} };
struct Derived3 : TBase<int> { void function(float) override {} };
int main()
{
Derived1 d1; // ERROR. Virtual functions are not implemented
Derived2 d2; // OK.
Derived3 d3; // OK.
}
Note that the functions are named function in this approach, not function1 and function2.
Your classes will remain abstract if you don't override all the abstract virtual methods. You have to do all of them if you want to instantiate the object.
Suppose that I have a heirarchy of several classes:
class A {
public:
virtual void DoStuff() = 0;
};
class B : public A {
public:
// Does some work
void DoStuff() override;
};
class C : public B {
public:
// Calls B::DoStuff and does other work
void DoStuff() override;
};
It can naively be implemented:
void Derived::DoStuff() {
Base::DoStuff();
...
}
This implementation has a serious problem, I believe: one always has to remember to call base implementation when overrides.
Alternative:
class A {
public:
void DoStuff() {
for (auto& func: callbacks_) {
func(this);
}
}
virtual ~A() = default;
protected:
template <class T>
void AddDoStuff(T&& func) {
callbacks_.emplace_back(std::forward<T>(func));
}
private:
template <class... Args>
using CallbackHolder = std::vector<std::function<void(Args...)>>;
CallbackHolder<A*> callbacks_;
};
Usage:
class Derived : public Base {
public:
Derived() {
AddDoStuff([](A* this_ptr){
static_cast<Derived*>(this_ptr)->DoStuffImpl();
});
}
private:
void DoStuffImpl();
};
However, I believe that it has a good amount of overhead when actually calling DoStuff(), as compared to the first implementation. In the use cases which I saw, possibly long costruction of objects is not a problem (one might also try to implement something like "short vector optimization" if he wants).
Also, I believe that 3 definitions for each DoStuff method is a little too much boilerplate.
I know that it can be very effectively solved by using inheritance pattern simular to CRTP, and one can hide the template-based solution behind interface class (A in the example), but I keep wondering -- shouldn't there be an easier solution?
I'm interested in a good implementation of call DERIVED implementation FROM BASE, if and only if derived class exists and it has an overriding method for long inheritance chains (or something equivalent).
Thanks!
Edit:
I am aware of an idea described in #Jarod42's answer, and I don't find it appropriate because I believe that it is ugly for long inheritance chains -- one has to use a different method name for each level of hierarchy.
You might change your class B to something like:
class A {
public:
virtual ~A() = default;
virtual void DoStuff() = 0;
};
class B : public A {
public:
void DoStuff() final { /*..*/ DoExtraStuff(); }
virtual void DoExtraStuff() {}
};
class C : public B {
public:
void DoExtraStuff() override;
};
I am not sure if I understood correctly but this seems to be addressed pretty good by the "Make public interface non-virtual, virtualize private functions instead" advice.
I think it's orignated in the Open-Closed principle. The technique is as-follows:
#include <iostream>
class B {
public:
void f() {
before_f();
f_();
};
private:
void before_f() {
std::cout << "will always be before f";
}
virtual void f_() = 0;
};
class D : public B{
private:
void f_() override {
std::cout << "derived stuff\n";
}
};
int main() {
D d;
d.f();
return 0;
}
You essentially deprive descendant class of overriding public interface, only customize exposed parts. The base class B strictly enforces that required method is called before actual implementation in derived might want to do. As a bonus you don't have to remember to call base class.
Of course you could make f virtual as well and let D decide.
Without RTTI and with virtual functions.
I encountered 2 different common solutions to provide type of the object:
with virtual method call and keep id inside the method:
class Base {
public:
virtual ~Base();
virtual int getType() const =0;
};
class Derived : public Base {
public:
virtual int getType() const { return DerivedID; }
};
with inline method call and keep id in the base class:
class Base {
int id_;
public:
virtual ~Base();
inline int getType() const { return id_; }
};
class Derived : public Base {
public:
Derived() { id_=DerivedID;}
};
What would be better choice in general and what is pro/cons of them?
If you choose the second option with an ID in every derived class, you'll have an extra member in every object you create. If you use the first option of a virtual function, you'll have an extra pointer in the vtable which only exists once per class, not per object. If the class will have more than one virtual function, the first option is clearly better. Even if not, I think it more closely corresponds to what people will expect.
You don't need virtual inheritance from the immediate base class, or any base class member variables to support this feature at all
struct Interface {
virtual void foo() = 0;
virtual int bar() = 0;
};
template<class T>
class Base : public Interface {
public:
int getType() const { return getTypeId(); }
static int getTypeId() { return T::ClassId; }
};
class Derived : public Base<Derived> {
public:
static const int ClassId = DerivedID;
virtual void foo() { }
virtual int bar() { return 1; }
};
Usage is like
Derived der;
Interface* iface = &der;
iface->foo();
iface->bar();
See a working sample here.
NOTE:
All of the types you use with a current configuration of such system need to be well known at compile time. This doesn't support a Plugin pattern based mechanism.
Okay, I'll take a stab...
"What are the pros/cons of them?"
Your first example virtual int getType() const =0; incurs extra processing overhead. A virtual function call can be more difficult for a CPU to preempt. This issue may be trivial.
Your second example inline int getType() const { return id_; } incurs extra runtime storage. And extra int is stored for every instance of every Base. This may also be trivial.
"What would be better choice in general?"
In general, avoid premature optimization. Choose the pure virtual function in the base class, because its correctness is enforced by the compiler and runtime.
How to call base class method if it is not abstract.
class WithAbstMethod {
public:
virtual void do() = 0;
}
class WithImplMethod : public WithAbstMethod {
public:
virtual void do() {
// do something
}
}
template<typename BaseT>
class DerivedClass : BaseT {
public:
virtual void do() {
BaseT::do(); // here is a question. How to modify code, so that do() is called if it is not abstract?
// do something
}
}
void main() {
DerivedClass<WithAbstMethod> d1;
d1.do(); // only DerivedClass::do() should be called
DerivedClass<WithImplMethod> d2;
d2.do(); // both WithImplMethod::do() and DerivedClass::do() should be called
}
Is it possible to do this using templates in compile-time without much code (instantiate DerivedClass::do() method with BaseT::do() call and without depending on BaseT type)?
Obviously, provide implementation in WithAbstMethod class is not an option. Code above is pseudo-code so may contain minor errors.
Actually, providing an implementation for WithAbstMethod::do() might be an option. Abstract functions are allowed to have an implementation.
void WithAbstMethod::do()
{
// do nothing...
}
I want to call a member function which is virtual (inheritance is used in most places to keep things simple), but I want to force calling it using non-virtual dispatch sometimes, in performance critical places, and in such places the exact type is known compile time. I do this for performance reasons, on a platform where virtual call performance is bad. For most functionality the overhead of virtual functions is fine, but for a few it is not. I would like to avoid duplicating all functions as both virtual and non-virtual.
Example:
class Interface
{
public:
virtual void Do(){}
};
class Implementation: public Interface
{
public:
virtual void Do(){}
};
void DoIt(Interface &func)
{
func.Do();
};
int main()
{
Implementation a;
DoIt(a);
// can DoIt be constructed as a template to avoid virtual dispatch?
return 0;
}
If you know the exact type you can do it as:
template <typename StaticType>
void DoIt(Interface &func)
{
static_cast<StaticType&>(func).StaticType::Do();
};
Where you need to manually downcast to the type you need (static_cast is fine if you do know the type). Then you need to qualify the method call, do disable dynamic dispatch.
struct DerivedType : Interface {
virtual void Do() { std::cout << "Derived::Do" << std::endl; }
};
struct MostDerived : DerivedType {
virtual void Do() { std::cout << "MostDerived::Do" << std::endl; }
};
void processDerived( Interface & iface ) {
DoIt<DerivedType>( iface );
}
int main() {
MostDerived obj;
DoIt<Derived>( obj ); // Will call Derived::Do
}
Note that using the qualified name will disable dynamic dispatch, and that means that it will not be dispatched to the runtime type of the object, but to the type that you tell it to call.
I think you are looking for Curiously Recurring Template Pattern (CRTP) which enables you static polymorphism :
template <typename Derived>
class Base {
public:
virtual ~Base() {}
void foo() { Derived::func_in_derived(); }
};
class Derived : public Base<Derived> {
public:
void func_in_derived() {}
};