This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
C++ overload resolution
I ran into a problem where after my class overrode a function of its base class, all of the overloaded versions of the functions were then hidden. Is this by design or am I just doing something wrong?
Ex.
class foo
{
public:
foo(void);
~foo(void);
virtual void a(int);
virtual void a(double);
};
class bar : public foo
{
public:
bar(void);
~bar(void);
void a(int);
};
the following would then give a compile error saying there is no a(double) function in bar.
main()
{
double i = 0.0;
bar b;
b.a(i);
}
In class bar, add
using foo::a;
This is a common 'gotcha' in C++. Once a name match is found in the a class scope, it doesn't look further up the inheritance tree for overloads. By specifying the 'using' declaration, you bring all of the overloads of 'a' from 'foo' into the scope of 'bar'. Then overloading works properly.
Keep in mind that if there is existing code using the 'foo' class, its meaning could be changed by the additional overloads. Or the additional overloads could introduce ambiguity and and the code will fail to compile. This is pointed out in James Hopkin's answer.
That is the way the language used to work. Prior to the using keyword, if you overrode one overloaded function, you had to overload them all:
class bar : public foo
{
public:
bar(void);
~bar(void);
a(int);
a(double d) { foo::a(d); } // add this
}
This annoyed enough people that the language committee added the using feature, but some old habits die hard; and the habitués† have a good argument.
As James Hopkins points out, by adding using, the programmer is expressing the intention that the derived class will, without warning, add any future overrides of foo::a() to its list of acceptable signatures.
Here is an example of what he describes:
#include <iostream>
class Base {
public:
virtual void f(double){ std::cout << "Base::Double!" << std::endl; }
// virtual void f(int) { std::cout << "Base::Int!" << std::endl; } // (1)
virtual ~Base() {}
};
class Derived : public Base {
public:
// using Base::f; // (2)
void f(double) { std::cout << "Derived::Double!" << std::endl; }
};
int main(int, char **) {
Derived d;
d.f(21);
return 0;
}
The output will be "Derived::Double!" because the compiler will promote the integer argument to a double. g++ 4.0.1 -Wall will not warn that this promotion occurred.
Uncomment (1) to simulate a future change to Base adding the method Base::f(int). The code compiles, again without warning even with -Wall, and "Derived::Double!" remains the output.
Now uncomment (2) to simulate a decision by the Derived programmer to include all Base::f signatures. The code compiles (without warnings), but the output is now "Base::Int!".
—
† I cannot think of an English word for "those who have the habit" and "addicted" is much too strong.
It is by design. Overload resolution is restricted to a single scope. It prevents some nasty cases of valid code changing meaning when additional functions are added to a base class or to namespace scope.
Related
I would like to enable C4263 (Visual C++) warning on our code base, however, the warning gives out some false positives. We would like to disable the warning such that only the false positives disappear. I tried to simplify the issue with some generic code:
class B {
public:
virtual void funcA();
virtual void funcB();
};
class D : public B
{
virtual void funcA(int);
virtual void funcB(int);
};
With this code we I get following warnings:
void D::funcA(int)' : member function does not override any base class virtual member function
void D::funcB(int)' : member function does not override any base class virtual member function
What I am trying to achieve is to disable the warning for funcA (or funcB) and let the rest of the class be affected by it.
I tried putting
#pragma warning(push)
#pragma warning(disable:4263)
.
.
.
#pragma warning(pop)
around funcA but that does not solve the problem. If the pragmas wrap the whole class that both of the warnings disappear.
Any ideas?
This is a strange error given the documentation for it:
https://msdn.microsoft.com/en-us/library/ay4h0tc9.aspx?f=255&MSPPError=-2147217396
'function' : member function does not override any base class virtual
member function
A class function definition has the same name as a virtual function in
a base class but not the same number or type of arguments. This
effectively hides the virtual function in the base class.
The last sentence is the interesting one, and it suggested to me that if you unhide the base class functions, the warning will no longer appear.
And indeed this is the case. The following code does not output C4263:
class B {
public:
virtual void funcA();
virtual void funcB();
};
class D : public B
{
using B::funcA;
using B::funcB;
virtual void funcA(int);
virtual void funcB(int);
};
The warning seems a little strange. If you're dispatching from the base class pointer, it doesn't matter what functions the derived class hides, as they won't be hidden when using a base class pointer. But herein lies the answer!
What's actually happening here is the compiler is guessing your intentions. Because you are introducing a new signature, it means you will be using either polymorphic or non-polymorphic dispatch using a derived pointer (not a base pointer). If you were not doing this, it would be impossible to call your overload. The compiler figures that if you are doing this, you will be hiding the un-overridden functions. And that's what the warning is about.
In an example:
struct Base
{
virtual void DoThing(int)
{
std::cout << "INT " << std::endl;
}
};
struct Derived: public Base
{
virtual void DoThing(char) // Add a function to handle chars
{
std::cout << "CHAR " << std::endl;
}
};
int main()
{
Derived *derived = new Derived;
Base *base = derived;
base->DoThing(1);
derived->DoThing(1);
derived->DoThing('a');
}
This outputs:
INT CHAR CHAR
The intention may have been to add an overload to handle a different case, but instead it's hiding all the existing overloads. The warning is correct given the rules of the language. The warning isn't exact, it's trivial to determine cases where it doesn't get invoked but it should. It in-fact does the opposite of false-warnings :)
To defeat this warning, the using declaration should be used.
This question already has answers here:
Why does a virtual function get hidden?
(6 answers)
Closed 8 years ago.
This is a continuation of my prior question. Note that the code below makes a virtual call at p->f(1.0) printing Derived::f(double).
#include <iostream>
#include <complex>
using namespace::std;
class Base
{
public:
virtual void f(double);
virtual ~Base() {};
};
void Base::f(double) { cout << "Base::f(double)\n"; }
class Derived : public Base {
public:
void f(std::complex<double>);
void f(double);
};
void Derived::f(std::complex<double>) { cout << "Derived::f(complex)\n"; }
void Derived::f(double) { cout << "Derived::f(double)\n"; }
int main()
{
Derived* p = new Derived;
p->f(1.0);
delete p;
}
If I just eliminate the member function void f(double); in Derived, the code makes a static call to Derived::f(std::complex<double>).
What was it that made the compiler change from a dynamic call in the first example to a static call in the second? I would appreciate some quote from the Standard.
Edit:
The answers to the question to which this was considered a dup don't cite the Standard, as I asked above. Thanks.
What was it that made the compiler change from a dynamic call in the first example to a static call in the second?
The lookup rules. Without the declaration of f(double) in derived (and lacking a using-declaration) the f(complex<double>) hides f(double) in the base. When the compiler does lookup for p->f(1.0) inside Derived, finds an overload and given a single option uses it. It never moves up to Base to check whether there are different overloads.
This question already has answers here:
Derived template-class access to base-class member-data
(3 answers)
Closed 8 years ago.
A coworker asked me today about code which looks somewhat like this:
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // compiler error
}
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
At first he was getting a compiler error saying that "foo()" was not found. OK, so he tried to change it to IBase<T>::foo();. While that compiled, it resulting in a linker error. So immediately, I recalled that I've seen this type of problem before and suggesting that he write this->foo(); instead. Viola! problem solved!
Then he asked me why didn't plain foo(); work? Isn't this->x(); essentially the same as x();? Honestly, I have no idea, but he piqued my interest. So here we are:
In summary:
virtual void bar() {
this->foo(); // works
//IBase<T>::foo(); // linker error
//foo(); // compiler error
}
The question is why is this-> required. And why won't the other options work?
Because the base class member is a dependent name - its meaning depends on the template parameter, and so isn't known until the template is instantiated. The name isn't looked up in the generic IBase template, since that might be specialised to give it a different meaning before instantiation.
Qualifying it with IBase<T>:: calls the base-class function non-virtually; that's generally not what you want, especially if (as here) it's a pure virtual function with no implementation. Hence the linker error when you tried that.
Qualifying it with this-> tells the compiler that it's a member, and any further checking is deferred until the template is instantiated. The function is still called virtually.
Imagine you are the compiler. You have just been reading through and compiling the code and now you have reached the bar function. In this function, you see that there is an attempt to do foo(). At this point, do you know what foo is? You don't. It could come from the base class, but you can't possibly know, because you don't know what T is yet. It's certainly possible that there might be a specialization of IBase for which foo is something else entirely.
When you stick this-> before the function call, it causes the compiler to treat it as a dependent name. That means the compiler will say "Okay, this depends on the type of this, which I do not know yet. I'll wait until later, when I know how the class is being instantiated, before I look for foo."
IBase<T>::foo(); gives a linker error because there simply is no definition for foo in IBase<T>.
#include <iostream>
template <class T>
class IBase {
public:
virtual ~IBase() {}
public:
virtual void foo() = 0;
};
int foo() { std::cout << "hello!\n"; }
template <class T>
class Base : public IBase<T> {
public:
virtual void bar() {
foo(); // which foo?!
}
};
template <>
class IBase<int> {
public:
virtual ~IBase() {}
//virtual void foo() = 0; -- no foo()!
};
class Derived : public Base<int> {
public:
virtual void foo() {
std::cout << "Hello World!\n";
}
};
int main() {
Derived d;
d.bar();
}
The above illustrates why C++ does not allow members of dependent type parents to be implicitly found.
When you call foo() in Base, which foo() should be called? The one in IBase<T> or the free function foo()?
Either we put the decision off until later, or we go with the free function foo().
If we only go with the free function foo() if one is visible, then subtle changes in #include order can massively change what your program does. So if it should call the free function foo(), it must error if one is not found, or we are completely screwed.
If we defer the decision until later, it means less of the template can be parsed and understood until a later date. This moves more errors to the point of instantiation. It also results in some surprising behavior, like in the above case, where someone might think "I'm calling the method foo()", but actually ends up calling the free function foo() with no diagnostic.
I've wanted to prevent even the hiding of base class non-virtual function for a while since I learned C++, and I'm not sure if this would be ethical, but C++ 11 features gave me an idea. Suppose I have the following:
bases.h....
#ifndef baseexample_h
#define baseexample_h
#include <iostream>
class Base{
public:
void foo() {
std::cout << "Base.foo()\n" << std::endl;
}
};
class Derived: public Base{
public:
void foo(){
std::cout << "Derived.foo()\n" << std::endl;
}
};
#endif
and main.cpp...
#include "bases.h"
#include <iostream>
int main()
{
Base base;
Derived derived;
base.foo();
derived.foo();
std::cin.get();
return 0;
};
for which the output is of course
Base.foo()
Derived.foo()
as the derived foo() function hides the base foo function. I want to prevent possible hiding, So my idea was to change the header file Base definition to:
//.....
class Base{
public:
virtual void foo() final {
std::cout << "Base.foo()\n" << std::endl;
}
};
class Derived: public Base{
public:
void foo(){ //compile error
std::cout << "Derived.foo()\n" << std::endl;
}
};
//......
Which seems to enforce what I want with a compiler error, prevention of overriding AND/OR hiding in c++, but my question is, is this a good practice since foo() was never a virtual function to begin with? Is there a downside to this since i'm kind of abusing the virtual keyword? Thanks.
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.
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;
}