Last active
July 15, 2016 02:02
-
-
Save tgockel/707aca8f4becdff679514331e26d243c to your computer and use it in GitHub Desktop.
Override method which has the same name as the class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** \file | |
* This is an attempt to answer the Stack Overflow question "Override method | |
* which has the same name as the class," wherein I ask how one would go about | |
* implementing a virtual method of some derived type which happens to have the | |
* same name as the method I need to implement. | |
* | |
* http://stackoverflow.com/questions/38384075/ | |
* | |
* Two methods are proposed, one using a typedef and the other using static | |
* polymorphism (see below for implementation). The conclusion is there are | |
* clear advantages to using the typedef solution, as the static polymorphism | |
* solution does not solve the issue for all potential callers (specifically: | |
* calls of the method inside of template functions). | |
**/ | |
/** \def USE_TYPEDEF | |
* Flip between 0 and 1 to toggle the different ways to hack around a class | |
* with a method named the same as the type. | |
* | |
* - 0: typedef foo_intermediate to be named foo | |
* - 1: static polymorphism: create a class named foo and derive from | |
* foo_intermediate | |
**/ | |
#define USE_TYPEDEF 0 | |
#include <iostream> | |
/** The base class with an annoyingly-named function \c foo. **/ | |
class base | |
{ | |
public: | |
virtual ~base() | |
{ } | |
virtual void foo() const = 0; | |
}; | |
/** In both solutions, you create an intermediate class which actually | |
* implements the foo method. | |
**/ | |
class foo_intermediate : public base | |
{ | |
public: | |
#if USE_TYPEDEF | |
/** In the typedef variety, you would actually implement the whole class in | |
* the thing I'm calling "intermediate" here. | |
**/ | |
virtual void foo() const override | |
{ | |
std::cout << "Typedef works!" << std::endl; | |
} | |
#else | |
/** In the static polymorphism solution, this forwards to the derived `foo` | |
* that I actually want to use. The definition must appear after the | |
* declaration of `foo`. | |
**/ | |
virtual void foo() const override; | |
#endif | |
}; | |
#if USE_TYPEDEF | |
// The typedef is pretty simple... | |
using foo = foo_intermediate; | |
#else | |
/** In the static polymorphism solution, you derive from the intermediate class | |
* and forward the constructor along. | |
**/ | |
class foo : public foo_intermediate | |
{ | |
public: | |
using foo_intermediate::foo_intermediate; | |
private: | |
friend class foo_intermediate; | |
/** Actual implementation for the foo function goes here. **/ | |
void foo_impl() const | |
{ | |
std::cout << "Intermediate class works" << std::endl; | |
} | |
}; | |
/** This would probably live in some CPP file. **/ | |
void foo_intermediate::foo() const | |
{ | |
static_cast<const ::foo*>(this)->foo_impl(); | |
} | |
#endif | |
#if USE_TYPEDEF | |
/** With the typedef, you can use a template parameter, since T is really a | |
* foo_intermediate, so calling foo is legal. | |
**/ | |
template <typename T> | |
void call_foo(const T& x) | |
#else | |
/** You must refer to calling foo with something that is not a type named foo | |
* (in this case, a reference to base). | |
**/ | |
void call_foo(const base& x) | |
#endif | |
{ | |
x.foo(); | |
} | |
int main() | |
{ | |
foo x; | |
#if USE_TYPEDEF | |
// Can only be called directly with the typedef | |
x.foo(); | |
#else | |
// With the intermediate class, you have to use an alias | |
base& rx = x; | |
rx.foo(); | |
#endif | |
// Demonstrates the same concept as above, but shows that the type name will | |
// leak out to templates | |
call_foo(x); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment