Useful links:
CRTP Sample Code
template <class Self>
struct Base {
// short cut to reference to dervied class
Self& self() { return static_cast<Self&>(*this); };
// reuse base code
int algorithm(int x) {
if (x > 42)
x = self().downsize(x);
x = self().crunch(x);
return x;
};
int downsize(int x) { return x % 42; };
int crunch(int x) { return -x; };
// static polymorphism
int run() {
return std::static_cast<Self*>(this)->_run_impl();
}
};
struct Derived : Base<Derived> {
// overriding base code
int downsize(int x) {
while (x > 42) x /= 2;
std::cout << "down!" << std::endl;
return x;
};
// static polymorphism
int _run_impl() {
return 1;
}
};
// better type safety
template <class T>
int foo(Base<T> &actor)
{
return actor.algorithm(314);
}
// more duck-typing
template <class T>
int bar(T &actor)
{
return actor.algorithm(314);
}
int main() {
Derived d;
std::cout << d.algorithm(420);
}
CRTP versus virtual functions
CRTP is a purely compile-time construct, meaning there’s no runtime overhead associated. Calling a virtual function through a base class reference (usually) requires a call through a pointer to function and thus incurs indirection costs and prevents inlining.
CRTP versus simply implementing everything in Derived
Base class code reuse.
Reference:
Can Virtual Classes(Interfaces) in C++ have Member Variables?
Strictly speaking, there is no such thing as a “virtual class” or “interface” in C++. If there is, it is artificial, i.e., developer-enforced. Generally, an interface has these characteristics:
- Declared within a namespace and may have public or private accessibility. Only public interfaces are emitted to metadata.
- It can include properties, methods and events.
- All interface members are implicitly public and virtual.
- Fields and static members are not permitted.
- Types that are used as properties, method parameters, or return values can only be fundamental types and enum class types.
So the answer is
- No, if you want an interface.
- Yes, if you just use abstract classes, but make them private and use public getters and setters.
Generally, it is considered better to make interfaces, pure interfaces. If there is really some information that is common to all derived classes (or simply to several of them), simply make that info another class and derive the implementation class from that also:
class Base {
virtual void method1() = 0; // pure virtual method 1
// virtual methods...
// no data
};
struct Common {
Data x;
// ...
};
class Derived : public Base, public Common {
// methods and data...
};
Reference:
What is the Non-virtual Interface Design Pattern and When to Use It?
The essence of the non-virtual interface pattern is that you have private virtual functions, which are then called(invoked) by public non-virtual functions (the non-virtual interface).
Advantage: The base class has more control over its behavior (the derived class can override less part of the whole thing).
Reference:
Shall I use virtual constructors/destructors?
There are no virtual constructors. From Bjarne Stroustrup’s C++ Style and Technique FAQ
A virtual call is a mechanism to get work done given partial information. In particular, “virtual” allows us to call a function knowing only any interfaces and not the exact type of the object. To create an object you need complete information. In particular, you need to know the exact type of what you want to create. Consequently, a “call to a constructor” cannot be virtual.
However virtual destructors are especially useful when you might potentially delete an instance of a derived class through a pointer to a base class:
class Base {
// some virtual methods
};
class Derived : public Base {
~Derived() {
// Do important cleanup
}
}
Base *b = new Derived();
// use b
delete b; // **Here's the problem!**
Always make base classes have virtual destructors when they are meant to be manipulated polymorphically. (Effective C++ Item 7)
Reference:
What Are Static Polymorphism and Dynamic Polymorphism?
todo.
Implicit inline
When Methods Written in Class Body
Inside the class body is considered to be inline by the compiler. If you implement outside of body, but still in header, you have to mark the method as ‘inline’ explicitly.
namespace test_ns{
class TestClass{
public:
// without this inline, multiple definition error will occur!
inline void testMethod();
};
void TestClass::testMethod(){
// some code here...
}
} // end namespace test_ns
Reference: