Skip to content

Instantly share code, notes, and snippets.

@tgockel
Last active July 15, 2016 02:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tgockel/707aca8f4becdff679514331e26d243c to your computer and use it in GitHub Desktop.
Save tgockel/707aca8f4becdff679514331e26d243c to your computer and use it in GitHub Desktop.
Override method which has the same name as the class
/** \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