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 withchar
Traits
is replaced withci_char_traits
Allocator
is replaced withstd::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 casePropertyName(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
What Is the Meaning of 'Struct X Typedef' VS. 'Typedef Struct X'
Opencv Fisheye Calibration Cuts Too Much of the Resulting Image
Extract C++ Template Parameters
Trying to Pass String Literals as Template Arguments
Boost.Python Call by Reference:Typeerror: No To_Python (By-Value) Converter Found for C++ Type:
Openssl::Ssl_Library_Init() Memory Leak
C++ Std::Tuple Order of Destruction
Why the Sequence-Operation Algorithms Predicates Are Passed by Copy
C++. Error: Void Is Not a Pointer-To-Object Type
Inlining Template Specialization
Using Std::Make_Unique with a Custom Deleter
Opengl: Glgeterror() Returns Invalid Enum After Call to Glewinit()
How to Differentiate (When Overloading) Between Prefix and Postfix Forms of Operator++? (C++)
How to Get the Address of the Std::Vector Buffer Start Most Elegantly
Why Does C++11 Not Support Anonymous Structs, While C11 Does