C++ Inheritance and Name Hiding

Name-hiding static member functions in C++: good practice?

The difference here is that the traits class is not polymorphic, so there will never be any confusion as to which interface is used.

ci_char_traits could of course be implemented with private inheritance, encapsulation or simply deferring to std::char_traits<>. All of these approaches would require more maintenance.

Update:

There has been some discussion in the comments on whether templates are polymorphic. I will elaborate.

The construct std::basic_string<char, ci_char_traits> causes template expansion of the template std::basic_string<class CharT, class Traits, class Allocator>. During this expansion, the following type substitutions are made:

  • CharT is replaced with char
  • Traits is replaced with ci_char_traits
  • Allocator is replaced with std::allocator<char>

Therefore, the class generated by the compiler is:

std::basic_string<char, ci_char_traits, std::allocator<char>>

This is not a polymorphic class.

This class will have a member typedef called std::basic_string<char, ci_char_traits, std::allocator<char>>::traits_type, which will unequivocally be the type ci_char_traits.

Therefore, this template expansion will result in a non-polymorphic class which uses the non-polymorphic class ci_char_traits to determine the behaviour of character-based operations such as comparison.

Which overload of eq and lt will be called by code in class std::basic_string<char, ci_char_traits, std::allocator<char>> is precisely defined, which is why in this case, it is not bad practice to overload these static member functions.

Multiple templated interface inheritance name hiding

A simplified reproduction:

struct A {
virtual void foo() = 0;
};

struct B {
virtual void foo() {}
};

struct C : A, B {
using B::foo;
};

C c; // error: C is abstract

The problem is that using B::foo doesn't override A::foo.

How does it relate to your code?

template<class Q, class A, class ... Rest>
struct ClientAdapter: public IClient<Q, A, Rest ...>, public ClientAdapter<Rest ...>
{
using ClientAdapter<Rest ...>::sendRequest; ...
void sendRequest(const Q& q, A& a) override ...
};

You inherit IClient with several pure virtual methods but override only one. The rest are still pure and make ClientAdapter abstract. The fact that the recursively-reduced ClientAdapter overrides sendRequest methods in recursively-reduced IClient doesn't matter, as these are two different instances of IClient.

If you inherit IClient virtually in all cases, the problem goes away because of inheritance via dominance (Live demo). Note that this mode of inheritance provokes a warning C4250 in MSVC. You can safely ignore it.

Intional use of name hiding for static function inheritance

This will "just work":

#include <iostream>

class Base {
public: static void foo() { std::cout << "Base::foo()\n"; }
};

class Derived1 : public Base { };
class Derived2 : public Base {
public: static void foo() { std::cout << "Derived2::foo()\n"; }
};

int main() {
Derived1::foo(); // prints "Base::foo()"
Derived2::foo(); // prints "Derived2::foo()"
}

It's the use of regular name shadowing, which works just the same for static members. The Base static implemenation is still available from Derived2 by means of rather funny syntax:

Derived2::Base::foo();

Preventing overriding and/or hiding base class function (C++ 11)

I'd say that, yes, it's bad practice. You introduced polymorphism when you didn't want it, just to prevent name hiding.

But what's so bad about name hiding? Obviously, for whatever reason, the design of Derived desires to hide the function foo in its base class; that is what it does — perhaps it makes its own call to Base::foo then performs some additional activity that is required within Derived.

Trying to subvert that is bad enough; trying to do it by co-opting language features that you don't want is even worse.

If you really need to call the base function, use derived.Base::foo(), but be aware that you are essentially breaking the API of the class Derived, which you should instead use as documented.

Derived class hiding base class same name method

Simple. You should write the 'using' declaration under public section of class as below. If you put the declaration in private section, Base functions are available to Derived class but they will become private members of Derived class. That is why your compiler is throwing 'inaccessible' error.

#include <iostream>
#include <complex>

using namespace std;

class Base {
public:
virtual void f( int ) {
cout << "Base::f(int)" << endl;
}

virtual void f( double ) {
cout << "Base::f(double)" << endl;
}

virtual void g( int i = 10 ) {
cout << i << endl;
}
};

class Derived: public Base {

public:
using Base::f;

void f( complex<double> ) {
cout << "Derived::f(complex)" << endl;
}

void g( int i = 20 ) {
cout << "Derived::g() " << i << endl;
}
};

int main() {
Derived d;

d.f(1.0);
}

In C++ polymorphism, how to avoid name hiding for functions (no matching function for call error)?

There are two problems here.

First:

Ship *ships[2] = {new Ship(), new PirateShip()};

this is an array of pointers to the Ship part of two objects. The first is a Ship, the second a PirateShip. But you only have a pointer to the Ship part of the PirateShip, so can only (directly) interact with it.

If Ship has virtual methods, then you could use RTTI and dynamic_cast to query if a given Ship* is pointing to the Ship part of a PirateShip like this:

auto* pirate = dynamic_cast<PirateShip*>(some_ship);

if pirate is non-null, then some_ship pointed at an Ship piece of a PirateShip.

Note that using dynamic cast is code smell; it probably means you should either improve the base class interface, or not have a pointer to base class here.


The second part is if you want to be able to call Ship::set from PirateShip*, you need to add

using Ship::set;

to the body of PirateShip.

Why is a property hiding Inherited function with same name?

Section 10.3.3 of the C# spec contains:

A derived class can hide inherited members by declaring new members with the same name or signature.

It doesn't say anything about the two members having to be the same kind of member. Note that even though one is a property and one is a method, there are still cases where they could be confused:

  • The property could be of a delegate type, e.g. Action<int, int> in which case PropertyName(10, 10) would be valid.
  • In some places where you use the property name, you could be trying to perform a method group conversion, so they'd both be valid.

Within the same class, we run into the rules of section 10.3:

  • The names of constants, fields, properties, events, or types must differ from the names of all other members declared in the same class.
  • The name of a method must differ from the names of all other nonmethods declared in the same class. [...]

The fact that you can't declare a method called get_myName is mentioned in section 10.3.9.1, as noted in comments.



Related Topics



Leave a reply



Submit