3

I'd like to alias a method of a base class in a derived method in C++ -- i.e. change only the name, not the signature.

The method's name is clear enough in its original scope (in the base class), but becomes ambiguous or misleading in the derived class. Thus, the obvious mitigation is to create an alias for the method in the base class. However, the long list of parameters the method takes is in flux as the derived class is being refined & retested. I'd like to avoid the boilerplate data entry task of re-typing the method signature, and alias it in a simpler manner, much like I can do with the 'using' directive for an inherited specialized constructor.

Simple example:

struct Person { int ID; void virtual sit() {}; void virtual walk() {}; void virtual run(int speed, int duration, int stride) {}; //method name in unambiguous in this scope Person(int id) : ID(id) {} //specialized c'tor }; struct Politician : Person { void speak() {}; void campaign() {}; //use this to 'run' for office //'sit' and 'walk' are clear enough, but 'run' is ambiguous in this scope, so alias it to 'sprint' void sprint(int speed, int duration, int stride) { Person::run(speed, duration, stride); } //the above works, but is a boat-load of boilerplate that I'd like to avoid using Person::Person; //use Person c'tor (avoids boilerplate) //using sprint = Person::run; //doesn't work - "'run' in 'struct Person' does not name a type" }; 

(Also consider a virtual class that inherits from multiple base classes, with one or more identically-named base-class methods. Such is my real-world application that I boiled down into this simpler example of the root need.)

Surely there is an easier way to create an alias for an unchanged inherited method, right?

10
  • Not really.... if you rename the method, it make the code harder to understand as one has to understand which to use depending if he has a pointer to base or derived class. Simply use different names from the beginning... Also, as sprint in not virtual, and you call base method from sprint that won't works as expected if you add a derived class to Politician You might argue that this can be fixed. Yes but given you didn't got it right, it already prove that your idea is error-prone... Also, given the argument of run method, it is clear its purpose so you don't need renaming here. Commented Apr 2, 2022 at 20:35
  • 1
    What do you expect Person* p = new Politician(...); p->run(...); and Politician* p = new Politician(...); p->run(...); each to call? Commented Apr 2, 2022 at 20:36
  • @user17732522 Politician* p = new Person(...): won't compile. Commented Apr 2, 2022 at 20:36
  • @IgorTandetnik Oops, right, mixed that up. Commented Apr 2, 2022 at 20:37
  • 3
    This feels like an incident of the Penguin is inherited from Bird, but Penguin can't fly. Commented Apr 2, 2022 at 22:15

2 Answers 2

1

The answer you asked for

template <typename ...T> decltype(auto) wrapper(T... t) { return func_whos_sig_keeps_changing(t...); } 

The answer you need

You're either violating the primary principal behind inheritance, or have not yet thought through how you intend to use this.

The whole point of inhering from person is so that somewhere in your code you can have this:

std::unique_ptr<person> person_ptr; ... ... person_ptr->run(); 

Without caring about what actual type of person it is.
If you can't do this with a politician, then its not a person and shouldn't inherit from person, at least not publicly.

Sign up to request clarification or add additional context in comments.

4 Comments

The shortcoming of contrived examples is the opportunities for reading between the lines, making inferences, and putting emphasis on ancillary artifacts of the example. Consider a class inheriting from multiple classes, with some identically-named methods: Think of Person and Politician as siblings instead of how presented, and give them each a 'run()' method with identical signatures). How to create a Senator class then, inheriting from both, alias the two run methods as 'sprint' and 'campaign', hide 'run', and then make Senator the base for StateSenator and USSenator derived classes.
@Jimbo1987 o agree contrived examples are problematic. As to your further examples, the simple answer is, I wouldn’t, most likely. I believe the way schools and books teach inheritance is fundamentally flawed. I believe interfaces should drive inheritance, not the other way around. To put it another way, I determine a need to treat several objects the same, and they all need to have x, y, and z, because that is what I’m using. I give that combination a name based on my usage and implement it on any classes that also need to be treated the same.
Thank you for the effort, nonetheless. I might should have explicitly referred to the inherited classes as 'interfaces' in my example. And I'm sure there were better examples to be conjured than this one. I gained a better understanding today of why people use foo & bar for everything.
Worth noting that the variadic template function solution here is not entirely the same as typing out the actual function signature: calling with the wrong number or types of arguments is not within the immediate context of template parameter substitution, meaning metaprogramming techniques using constraints or SFINAE won't work nicely. The wrapper also can't help figure out the correct type for an initializer list argument or pointer to overloaded function argument.
1

Evidently the answer is: It cannot be done the easy (dynamic & elegant) way. It has to just be 'hard-coded' the way I showed as the example of how I wanted to avoid having to do it. This was proposed for the C++ standard and rejected because the need was "unlikely to become common enough to warrant a separate language feature," and "not likely to become everyday work for novices."

The proposed syntax to rename/alias an inherited method, adapted to my example, was:

void sprint() = Person::run;

Credit to SO users Max Lybbert and Tomalla for finding it in Design & Evolution of C++ section 12.8.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.