Reputation: 119
I have a set of classes (SubClassA, SubClassB, etc) that inherit from SuperClass. These classes have a myriad of methods that are exactly identical between the subclasses, except that they return a reference to *this (a.k.a. SubClassX&). The return type can't be deprecated to SuperClass& either, because then the subclass-specific functions and members wouldn't be accessible.
I'm looking for a short, clean way to implement this so that I don't have to replicate the method code in each subclass.
The best thing I've been able to come up with is something like this (pseudo-code), but I'm not sure if this would even work:
//methods.cpp
SUBCLASS& general_method_1() {return *this;}
SUBCLASS& general_method_2() {return *this;}
And then:
#define SUBCLASS SubClassA
class SubClassA : public SuperClass
{
#include "methods.cpp"
SubClassA& specific_method_1() {return *this;}
}
#define SUBCLASS SubClassB
class SubClassB : public SuperClass
{
#include "methods.cpp"
SubClassB& specific_method_2() {return *this;}
}
Not to mention this seems kind of hackish and difficult to interpret. Any ideas?
EDIT: I should have mentioned that I will need to be able to polymorphically access the subclasses through pointers to SuperClass. For example, the following needs to be valid:
SuperClass* subclass[2];
subclass[0] = new SubClassA;
subclass[1] = new SubClassB;
Upvotes: 2
Views: 338
Reputation: 119877
CRTP.
template <class Derived> class Base
{
Derived& derived() { return static_cast<Derived&>(*this); }
};
class Derived1: public Base<Derived1>
{
};
class Derived2: public Base<Derived2>
{
};
In order to access things polymorphically, one needs to split Base in two:
class Base
{
public:
virtual ~Base() {}
// virtual Base& derived() = 0; -- note: this will NOT work!
};
template <class Derived> class BaseImpl : public Base
{
Derived& derived() { return static_cast<Derived&>(*this); }
};
class Derived1: public BaseImpl<Derived1>
{
};
class Derived2: public BaseImpl<Derived2>
{
};
int main()
{
Base* b[2] = { new Derived1, new Derived2 };
}
Upvotes: 1
Reputation: 6834
It's not clear from your question whether all you require is to make use of covariant return types
and a template.
For example:
class SuperClass
{
public:
virtual SuperClass& method() = 0;
};
class SpecificA : public SuperClass
{
public:
int specificMethodA();
};
class SpecificB : public SuperClass
{
public:
int specificMethodB();
};
template<class Specific>
class SubClass : public Specific
{
public:
virtual SubClass& method() { return *this; }
};
int main()
{
SubClass<SpecificA> scA;
SubClass<SpecificB> scB;
scA.method().specificMethodA();
scB.method().specificMethodB();
}
Upvotes: 0
Reputation: 75727
The way I would do it:
class Dystopia {
using This = Dystopia;
This& beHappy() {
// make me happy
return *this;
}
};
class Utopia : public Dystopia {
using This = Utopia;
This& beHappy() {
return static_cast<This&>(Dystopia::beHappy());
}
};
The main point here is that when you are in a derived class you can explicitly call the base method.
Note that the typedef is just a commodity (is not required).
As a sidenode: avoid macros in C++. Can’t emphasise this enough: Avoid macros!!. Armageddon will come in macros and good luck then debugging the End of the world.
Upvotes: 1
Reputation: 206627
I am going to suggest the following:
Example:
DeclareFunctionsMacros.h
#define DECLARE_FUNCTIONS(THIS_CLASS) \
THIS_CLASS& general_method_1(); \
THIS_CLASS& general_method_2();
DefineFunctionsMacros.h
#define DEFINE_FUNCTIONS(THIS_CLASS) \
THIS_CLASS& THIS_CLASS::general_method_1() { return *this; } \
THIS_CLASS& THIS_CLASS::general_method_2() { return *this; }
SubClassA.h
#include "DeclareFunctionsMacros.h"
class SubClassA : public SuperClass
{
DECLARE_FUNCTIONS(SubClassA);
SubClassA& specific_method_1() {return *this;}
}
SubClassA.cc
#include "DefineFunctionsMacros.h"
DEFINE_FUNCTIONS(SubClassA)
This will allow you to alter definitions of the macros used in defining the functions without needing to recompile everything that #include
s SubClassA.h
.
Upvotes: 0