C++: rationale behind hiding rule - c++

What's the rationale behind the hiding rule in C++?
class A { void f(int); }
class B : public A { void f(double); } // B::f(int) is hidden
If it is a meaningful feature I think it should also be possible to hide functions without defining new functions with the same name: something like this:
class B : public A { hide void f(double); }
but this is not possible.
I don't think it simplifies compilers job, since compilers must anyway be able to unhide functions when you explicitly use the using directive:
class B : public A { using A::f; void f(double); } // B::f(int) NOT hidden
So, how come there is a hiding rule?

It's an hairy question, but apparently the idea is that this hiding feature helps avoiding subtle bugs when making changes to a base class (that could otherwise "steal" calls that before would have been handled by the derived class). Still a change in a base class can influence the result of compilation of derived classes so I don't think I understand 100% this explanation.
I agree that this topic is so frequently discussed that probably the hiding actually increases the amount of "surprises" in C++ programmers.
A detailed discussion about this issue can be found here...

i don't know the original rationale, but since hide or not hide are about equally bad choices wrt. to functions, i'm guessing the rationale is to have uniform rules: the same as for names defined in nested curly-braces scopes.
the hiding helps you in some ways.
adding a method to a base class will by default not affect overload resolution for a derived class.
and you do not run afoul of overload resolution by some mishap directing your call with say argument false, to a base class method with formal argument void*. such things.
cheers & hth.,

I'm sure I've seen this case offered by a C++ bigwig, not sure which:
struct Base {
void f(const Base&);
};
struct Derived : Base {
using Base::f;
void f(double);
};
int main() {
Derived d;
d.f('a'); // calls Derived::f
}
Now, add void f(int); to Base, and the meaning of main changes - it calls Base::f because int is a better match for char - it's an integer promotion rather than a standard conversion.
It's not clear whether that change to the base would really be intended by the programmer to catch calls with char, so requiring using to be explicit means the default behavior is that the change doesn't affect the calling code. I believe it's a marginal call, but I think the committee decided that base classes in C++ were fragile enough as they are, without this too :-)
There's no need for a "hide" keyword because there's no comparable case for hiding "f" from the Base when it isn't overloaded in Derived.
Btw, I've chosen the types, and char is deliberately incongruous. You can get more subtle cases with int vs unsigned int rather than int vs char.

Another reason for hiding base class's member function (with same name but different signatures) might be due to ambiguity caused by optional parameters. Consider the following example:
#include <stdio.h>
class A
{
public:
int foo(int a, int b=0)
{
printf("in A : %d, %d\n", a, b);
}
};
class B : public A
{
public:
int foo(int a)
{
printf("in B : %d\n", a);
foo(a); //B:foo(a) will be called unless we explicitly call A:foo(a)
foo(a, 1); // compile error: no matching function for call to B:foo(int&, int)
}
};
int main()
{
B b;
b.foo(10);
return 0;
}
If the foo method in base class hadn't become hidden, it wouldn't be possible for compiler to decide whether A::foo should be called or B::foo since the following line matches both signatures:
foo(a);

Probably, the reason is template specialization. I give you an example:
template <int D> struct A { void f() };
template <> struct A<1> { void f(int) };
template <int D>
struct B: A<D>
{
void g() { this->f(); }
};
The template class B has a method f(), but until you don't create an instance of the class B you don't know the signature. So the call this->f() is anytime "legal". Both GCC and CLang don't report error until you create the instance. But when you call the method g() on a B<1> instance they indicate the error. So the hiding rule keep simpler to check if your code is valid.
I report the last part of code used in my example.
int main (int argc, char const *argv[])
{
B<0> b0; /* valid */
B<1> b1; /* valid */
b0.g(); /* valid */
b1.g(); /* error: no matching function for call to ‘B<1>::f()’ */
return 0;
}

Related

Derived class doesn't override a virtual function with a different signature

I have a derived class where I want one of the functions to override its version in the base class, but have a different signature.
Simple example:
#include "stdio.h"
bool use_foo = false;
class Foo {
public:
virtual int func(double x) { printf ("%f in Foo!\n", x); }
};
class Bar : public Foo {
public:
int func(short x) { printf ("%d in Bar!\n", x); }
};
int main () {
Foo* A;
if (use_foo)
A = new Foo;
else
A = new Bar;
A->func(2);
return 0;
}
The above code would call the base class copy even though A was allocated as the derived class:
> g++ test.cpp -o test -O3 && ./test
2.000000 in Foo!
Because (as far as my understanding goes) the argument can be converted to match the base class signature, and the derived class doesn't override it because of this difference (but wouldn't it hide it in that case?). If I change the base class function to have short as argument as well, the derived class does manage to override it.
Is there a simple way to convince the call to use the correct function based on the pointer? I could add another function like this:
class Bar : public Foo {
public:
int func2(short x) { printf ("%d in Bar!\n", x); }
int func(double x) { func2(x); }
};
But then I would convert the arguments all the time (short->double->short), and this function is performance critical. Is there a better way?
These function signatures are not identical:
virtual int func(double x) {...} // base class
int func(short x) {...} // derived class
One uses double parameter, the other uses short. For overriding to occur several conditions must be met. Identical parameter types of the base and derived functions being one of them. Bellow is the excerpt from the "Modern Effective C++" book by Scott Meyers on all the requirements:
• The base class function must be virtual.
• The base and derived
function names must be identical (except in the case of destructors).
• The parameter types of the base and derived functions must be
identical.
• The constness of the base and derived functions must be
identical.
• The return types and exception specifications of the base
and derived functions must be compatible.
Alternatively, make the signatures the same and perform the casting inside a derived function body:
int func(double x) override {
short temp = static_cast<short>(x);
// ...
}
What sense does this make anyway? The reason you use a virtual function is that the caller should only be required to know the base class, and thus only the base-class signature.
In other words, code which has, say, a Foo& or a Foo* or a std::unique_ptr<Foo>, only knows about the double version of your function anyway. It will pass a double when it calls func, because what else should it do?
Perhaps what you really want to do is the subclass implementation of the function to convert the double to a short. Here's an example for that, which also gets rid of the printf in favour of a type-safe C++ stream:
class Bar : public Foo {
public:
int func(double x) { std::cout << static_cast<short>(x) << " in Bar!\n"; }
};
Note that since C++11, you are encouraged to use override to mark overriding functions.
and this function is performance critical.
Should a performance-critical function be virtual at all?
Have you actually measured the speed? Is there a noticeable delay? Or are computers too fast anyway?

`using` Only Some Overloads Of A Base Class

Consider a class b with two overloaded methods of foo:
struct b {
void foo(float) {}
void foo(const char *) {}
};
If I derive d privately from b, I can use using to expose b's foo:
struct d : private b {
using b::foo;
};
However, this exposes all overloads. Is there a way to expose only one of them (say, the float one)? For example, in the following, I'd like the last line to fail compilation:
d t;
t.foo(3.13); // d should have this overload
t.foo("hello"); // d shouldn't have this overload
I tried various ways of writing
using b::<i mean only void foo(float), dammit!>
but couldn't get any of them to compile.
Also, obviously it's possible to define in d just the required overload calling b's overload
struct d : private b {
void foo(float f) { b::foo(f); }
};
but the question is if it's possible to do this tersely with using only.
No, that is not possible. A using declaration, just like any other declaration, operates on names.
using b::foo; introduces the name foo into the declaration's containing scope, such that it refers to whatever b::foo refers to. The name b::foo refers to a "family" of overloaded functions, so after the using-declaration, the name foo refers to the same.
If you want to "publish" only some overloads, you have to do it using the trampoline functions you've shown:
struct d : private b {
void foo(float f) { b::foo(f); }
};
As mentioned by #Angew in his answer, an using declaration introduces names in a namespace.
Because of that, you can't pick only your preferred ones up, but you can still do the opposite and = delete the ones you don't want to expose:
struct B {
void f() { }
void f(int) { }
void f(int, char) { }
};
struct D: B {
using B::f;
void f(int) = delete;
};
int main() {
D d;
d.f();
d.f(0, 'c');
// this won't work
// d.f(0);
}
This is not exactly what you were looking for, but it is a workaround to obtain almost the same result.
It follows a comment made by #Yakk that is worth quoting in the answer:
Note that a deleted overload is not the same as not having one. If missing a different overload may be selected, while if deleted it may be instead selected and generate an error.
This is right, if the solution above works for the OP mostly depends on the real problem.
I cannot say that, but still this is a viable solution for some cases

how to override a function (in an abstract base class) with a covariant parameter

I have several classes D with public sections of the form:
class D
{
public:
D& foo();
void bar(D&);
}
I'd like to create a single abstract class from which they all derive.
My (naive) attempt was:
// in .h file
class B
{
public:
virtual B& foo() = 0;
virtual void bar(B&) = 0;
}
class D : public B
{
public:
D& foo() override;
void bar(D&) override;
}
// in .cpp file
D& D::bar() {return *(new D());}
void D::foo(D& d) {}
This failed to compile for (what I eventually realized was) a fairly sensible reason: Any function overriding the function
void bar(B&)=0;
must be defined for any parameter which is a reference to type B. The supplied candidate
virtual void bar(D&) override;
is only defined for (the smaller collection) of parameters which are references to type D.
Note that this is not a problem with the function foo. Indeed, if you comment out the three lines with bar, everything compiles fine.
I think that the technical explanation for this phenomenon is that C++ does not support covariance in parameters (but it does support contravariance in parameters).
The answer to the post C++ covariance in parameters suggests that I can't define an interface (i.e. an abstract class) for my classes D.
Is there some simple or conventional way to create a single "interface" for all my classes D? Alternatively, perhaps there is a different design pattern for hiding the different implementations of these classes.
Thanks in advance for your comments and suggestions.
dan
You can't, and for good reason. A derived class can't add preconditions that are more restrictive than the interface it derives from without breaking every principle of OOP that exists. By requiring the parameter to be more specific in your implementation of the interface this is exactly what you are doing.
An argument could be made that something like this could be useful:
struct IfaceA {};
struct IfaceB : IfaceA {};
struct Base { void f(IfaceB &); };
struct Derived : Base { void f(IfaceA &); };
This lessens preconditions rather than increase them, so it's OK. It's simply not done in C++, or any other language I'm aware of for that matter, so you just can't do it.
In both cases you can make an overload with the alternative parameter type and call the overridden version.
It's the opposite case with return types. Return values are post-conditions. You can make post conditions more specific, but can't make them more broad. So you can return your derived type but can't broaden it by returning a more abstract type. C++ implements covariant returns though at least one, very commonly used compiler does it very badly so that there are numerous bugs.
Based on the code that you have provided you have tried to override two diferent function signatures.
The best option you have is use the same signature, and then cast the result.
A simple example,
// in .h file
class B
{
public:
virtual B* foo() = 0;
virtual void bar(B*) = 0;
};
class D : public B
{
public:
B* foo() override;
void bar(B*) override;
};
// in .cpp file
B* D::foo()
{
D* p=new D();
return p;
}
void D::bar(B* d)
{
D* casted=dynamic_cast<D*>(d);
}
int main(void)
{
D son;
B* father=dynamic_cast<B*>(son.foo());
}
I hope that this can solve your problem, or at least give you a clue.
Could you use a templated base class?
template <typename Deriving>
struct Base {
virtual Deriving& foo() = 0;
virtual void bar(Deriving&) = 0;
};
struct Deriving : public Base<Deriving> {
...
};
You don't have a single interface class, but there is a single interface template, which is sometimes versatile enough.

Why doesn't private inheritance resolve ambiguity for static functions ? (tested in MSVC)

I'm wondering why a call to a static function is ambiguous, even when one of the two is obviously impossible to call as it is private.
I was hoping I could use private / protected inheritance to help the compiler solve the ambiguity.
Is it specific to MSVC or is it somehow specified in the standard ?
struct A
{
static int num() { return 0; }
};
struct B
{
static int num() { return 1; }
};
struct C : public A, private B
{};
int main()
{
C::num(); // Ambiguous access of num
}
The background is that I was trying a way of reusing an overloading behavior (the one in A) in many derived classes (C,D,E,F,G) by inheriting it, to adhere somehow to a rule of Don't Repeat Yourself.
Yes it is specified in the C++ Standard, section §3.4 [basic.lookup]
The access rules (Clause 11) are considered only once name lookup and function overload resolution (if applicable) have succeeded
Name lookup doesn't care about accessibility : it finds both A::num and B::num, so there is an ambiguity for the compiler.
You can explicitly call A::num with :
C::A::num();
If you explicitly try to call B::num, then your compiler will indeed emit an access error :
C::B::num(); // Error
You can also explicitly bring the base name into scope within the derived class, which will fix the ambiguity :
struct C : public A, private B
{
using A::num;
};
To help compiler you can do this
struct C : public A, private B
{
using A::num;
};
Private members are intentionally considered for overload resolution.
Suppose you have
class C {
public:
static void f(int);
static void g();
private:
static void f(long);
};
void C::g() {
f(0L); // okay
}
void g() {
f(0L); // error, does not silently call f(int)
}
Making only public members available during overload resolution causes highly surprising re-interpretations of code, where code that looks like it should work the exact same way would silently call different overloads.
Making such code an error was considered less troublesome than the alternative.

a way in c++ to hide a specific function

i have an inheritance struct A : public B, i want to hide individual functions from B, is this possible?
i know the opposite is possible using using BMethod in the A declaration.
cheers
If you want to selectively hide functions from B it does not make much sense to use public inheritance in the first place.
Use private inheritance & selectively bring methods from B into the scope of A:
struct B{
void method1(){};
void method2(){};
};
struct A : private B{
using B::method1;
};
A a;
a.method1();
a.method2(); //error method2 is not accesible
There is an issue here: this would be a direct violation of the Liskov Substitution Principle, namely A would not act as a B any longer.
If you wish to reuse B implementation, the solution is simply to do so:
class A
{
public:
void foo() { return b.foo(); }
void bar() { return b.bar(); }
// ...
private:
B b;
};
Don't abuse inheritance, use composition instead
The using keyword can be used to change visibility
struct A
{
void method1();
};
struct B: public A
{
void method2();
private:
using A::method1;
};
Aside from the ways described in the previous answers—composition, private inheritance, and non-private inheritance but with the inherited method declared private—another way is to explicitly delete the inherited method:
#include <iostream>
struct A {
void foo() { std::cout << "foo\n"; }
};
struct B : A {
void foo() = delete;
};
int main() {
B b;
b.foo(); // COMPILER ERROR
}
Although the b.foo() call produces a compiler error, client code can still call the base class’s version by qualifying with the base class identifier A:
b.A::foo(); // compiles, outputs 'foo' to console
This explicit deletion way works when foo is not a virtual non-deleted method in A. By C++11 Standard §10.3/16, this explicit deletion is ill-formed when the deleted method in the derived class overrides a virtual non-deleted method of the base class. For more info on this restriction, see the answers to the SO question C++11 Delete Overriden Method.
You can't "hide it" per se, but you can make it a compile time error to call it. Example:
struct A
{
void AMethod() {}
};
class B : public A
{
void AMethod() {} //Hides A::AMethod
};
int main()
{
B myB;
myB.AMethod(); //Error: AMethod is private
static_cast<A*>(&myB)->AMethod(); //Ok
return 0;
}
Examples on codepad with the error, and without.
That all said, despite this being possible, you really shouldn't do it. You'll confuse the hell out of clients.
EDIT: Note that you can also do this with virtual functions (And with the error).
To those that are suggesting composition... this might not be the best possible way of going about things. My understanding is that the Liskov Substitution Principle only states that there's the possibility of the functions from the base class being used on the child, not that they necessarily should be. For example, for a particular base class you may have multiple functions that essentially perform the same operation, but for different specific cases. In the derived class you may want to abstract these public functions away in favor of simplifying the user's interface. This is where private inheritance can be used. Private inheritance might also be a necessity, if we have protected functions in the base class that we don't want the user of the base class to call, yet would be invaluable to the derived class.
In short, if you HAVE to, use private inheritance, but composition is preferred in most cases.
There is yet another approach.
class A{
void f1();
void f2();
void f3();
}
class BInterface{
void f2();
void f3();
}
class B : public A, BInterface
{
}
BInterface b = new B();
b->f1(); //doesn't work since f1 is not declared in BInterface
b->f2(); //should work
b->f3(); //should work
delete(b);
Use BInterface as a filter for inherited classes to exclude undesirable methods. Liskov Substitution principle isn't violated in this case since an object of BInterface class is not an object of A class even though that an object of B class is an object of BInterface class.
If the methods are private in B, then they will remain hidden to a even if you use public inheritance.
Can't alter the visibility of the original method.
You could create a method in struct A with the same name and have that method be private, but that doesn't prevent the method from being called when an instance of struct A is being referenced by a variable of type B.
Why don't you make it Virtual in the base class and override it in its Children? (more help)