This question already has answers here:
Overriding C++ virtual methods with multiple signatures [duplicate]
(2 answers)
Closed 6 years ago.
Why is this not compiling?
error C2660: 'Concrete::WriteLine' : function does not take 1 arguments
I know if i add the Line:
//using AbstractBase::WriteLine;
it works, but i dont understand why.
#include "iostream"
class AbstractBase
{
public:
virtual void WriteLine() = 0;
virtual void WriteLine( int i )
{
std::cout<<"AbstractBase"<<std::endl;
}
};
class Concrete : public AbstractBase
{
public:
//using AbstractBase::WriteLine;
virtual void WriteLine()
{
std::cout<<"Concrete Sub Class"<<std::endl;
}
};
int main()
{
Concrete ff;
ff.WriteLine();
ff.WriteLine(1);
return 0;
}
Can someone explain me what happens here.
Thanx
Does anyone knows if this behavior is a defined behavior from the C++ standart.
Is it mentioned in the C++ standart?
Or is it just a kind of compiler behavior?
Once you declare a function:
void WriteLine()
in derived class it hides all the base class functions with the same name.
The above function which takes no parameters hides the function with same name and taking one parameter, Since compiler cannot find a function with one parameter it reports a error.
The line:
using AbstractBase::WriteLine;
enables(brings in scope) all the hidden names from the Base class in your derived class and hence the function taking one parameter is available.
Good Read:
What's the meaning of, Warning: Derived::f(char) hides Base::f(double)?
Method hiding happens. The other function in the base class is hidden by the function with the same name, although it has a different signature.
To solve this, you can use a using directive:
using AbstractBase::WriteLine;
in the derived class:
class Concrete : public AbstractBase
{
public:
using AbstractBase::WriteLine;
//using AbstractBase::WriteLine;
virtual void WriteLine()
{
std::cout<<"Concrete Sub Class"<<std::endl;
}
};
Declaring a function in a derived class hides all functions with the same name in the base class - they are not considered as potential overloads of the derived class functions.
Adding the using declaration brings the hidden functions back into the scope of the derived class, and they are considered as potential overloads along with the derived class functions.
The problem is that Concrete::WriteLine is hiding all AbstractBase::WriteLines. You can add
using AbstractBase::WriteLine;
to your derived class.
Related
This question already has answers here:
C++ inheritance and name hiding [duplicate]
(3 answers)
Why does an overridden function in the derived class hide other overloads of the base class?
(4 answers)
Closed 2 years ago.
maybe this is a FAQ, but all exisiting questions I found were referring to methods with identical signature, i.e. real overrides.
My problem boiled down to a minimal example:
class A
{
public:
enum class Enumeration {Value_1, Value_2};
void SetValue(Enumeration e) //!! this is what it is about
{
m_member = e;
}
Enumeration m_member;
};
class B
{
public:
void SetValue(std::string value) // same method name, different parameter type -> different method signature
{
m_stringMember = value;
}
std::string m_stringMember;
};
class C : public A, B // inheriting both SetValue() methods
{
};
int main(int argc, char **)
{
C test;
test.SetValue(A::Enumeration::Value_1); // C2385 - ambiguous access
test.SetValue("Test"); // C2385 - ambiguous access
}
Compiler: VC++ 15
The call to both test.SetValue() functions gives me a C2385:
error C2385: ambiguous access of 'SetValue'
note: could be the 'SetValue' in base 'A'
note: or could be the 'SetValue' in base 'B'
Regarding the error message, I object. It "could not" be the SetValue in the other base class because the parameter type mismatches. It should be clear to the compiler which method matches the call.
Obviously (verified), overloading works fine if I put both methods into class A and instantiate A:
class A
{
public:
enum class Enumeration {Value_1, Value_2};
void SetValue(Enumeration e)
{
m_member = e;
}
void SetValue(std::string value)
{
m_stringMember = value;
}
Enumeration m_member;
std::string m_stringMember;
};
int main(int argc, char **)
{
A test;
test.SetValue(A::Enumeration::Value_1);
test.SetValue("Test");
}
What makes the difference here? How do these two method declarations interfere? Is there a way of overcoming this which does not require changing the name of SetValue() in one of C's base classes?
This has to be a duplicate, but I can't find it.
Overloading applies to functions with the same name defined in the same scope. In the code in the question, the two functions are defined in different scopes, one in class A and one in class B, so they do not overload, and the compiler is not allowed to pick one or the other. So the call is ambiguous.
The way to resolve this is to tell the compiler which one you want. From outside it's ugly: test.B::SetValue("Test");, if I remember correctly.
The reason for this is maintainability. Suppose that the class A in the example came from a third-party library and did not have a function named SetValue. In the code in the question, test.SetValue("test") would be fine: it calls B::SetValue(std::string), converting the string literal into a std::string. Now you install a new version of that third-party library, and A now has a new member function, A::SetValue(const char*). If the compiler applied overload resolution to those two SetValue functions, it would call the new one, and the behavior of your previous code would change: it would call A::SetValue instead of B::SetValue. That makes code fragile.
Since there seems to be a lot of confusion here: this is not name hiding. The usual example of name hiding occurs when a base class defines a name, and a class derived from that base also defines a name. The one in the base is said to be hidden; formally, the compiler simply stops looking when it sees the one in the derived class. The same thing applies when a class defines a name that's the same as a name in global scope; the compiler doesn't look outside the class after it's found the name inside the class.
This question already has answers here:
Why does an overridden function in the derived class hide other overloads of the base class?
(4 answers)
Closed 5 years ago.
Suppose I have the following classes:
class Base
{
public:
virtual void myMethod()
{
}
virtual void myMethod(int x)
{
}
};
class Derived : public Base
{
};
In this situation the following code compiles just fine.
int main(void)
{
Derived obj;
obj.myMethod();
return (0);
}
The problem arises when I try to override one of myMethods like below.
class Derived : public Base
{
public:
virtual void myMethod(int x)
{
}
};
Now the code won't compile and gives the error:
error C2660: 'Derived::myMethod' : function does not take 0 arguments
I have overridden one of the overloaded functions and apparently this has hidden the other one from Derived class. To get rid of the error I have to override all the overloads. This is against my expectation and doesn't seem rational to me. Why does this code behave this way?
The problem can be reproduced here.
Indeed, declaring a function in one scope hides anything with the same name in a wider scope, so your override in the derived class hides the overload in the base class.
This is usually not a problem, since you'd usually interact with polymorphic classes via the base class; and usually what you want, since it prevents changes to the base class from unexpectedly changing the behaviour of code that does interact with the derived class.
But you can easily bring it back into the derived class's scope if you want:
using Base::myMethod;
or refer to the function by qualified name:
obj.Base::myMethod();
your compiler is 100% right.
you overloaded your function to take an integer as argument, then this function hid all of the base class function - so obj calls myMethod(int) be default , yet you don't provide your function an integer.
if you fix your code to be
obj.myMethod(4);
the problem solved.
when overriding a function in the derived class - it hides all the other base class overloads. one can still call the base class with this syntax :
obj.Base::myMethod();
In more in depth answer , this is WHY it happens.
first of all, we need to understand HOW the compiler compiles Object oriented code. remember - the functions compiles into assembly commands and they sit in the code segment. the variables compiles into rows of memory that sit wither in the stack , heap or data segments. functions sits in on part of the application , the variables in a complete different areas. how does the compiler compile a class with variables AND functions? well, it doesn't. the idea goes like this:
let's say a have a class named X with some variables and some functions
1) take all the member functions and bring them out of the class
2) add another argument to each-now-globally-declared functions - const X* this
3) each time you see the syntax x.someFunc(args..) change it to be someFunc(args..,&x)
4) in the functions - if you don't recognize a symbol - try attaching it a this-> and see if you can compile this
5) compile X as C struct and the other as C functions
6)do the same for derived classes
(of course , there is the virtual table issue , but let's stop here)
IN YOUR EXAMPLE:
the psuedo code that might represent the compiler parsed-code is
struct Base{}
struct Derived{}
void myMethod(const Base* this);
void myMethod(int x,const Base* this);
void myMethod(int x, const Derived* this);
//what you tried to do is :
myMethod (&obj);
but the compiler can't find any function that matches these arguments!
this is not very intuitive for someone who don't initially knows how object oriented compiles, but it makes more sense after understanding this compiling procedure.
By overriding the function in Derived class you hide all overloaded implementations of that function name existing in Base class.
Therefore overriding void Base::myMethod(int) with void Derived::myMethod(int) generates code only for void Derived::myMethod(int) and doesn't for void Derived::myMethod().
As mentioned before you can call Base's function explicitly:
obj.Base::myMethod().
This question already has answers here:
C++: rationale behind hiding rule
(5 answers)
Closed 9 years ago.
Before asking my question I tried searching the web, but I'm not sure what terms I need to use, and I didn't find an explanation to my problem. If such an answer allready exists, feel free to just point me to it :)
Here is a small sample:
class IObject;
class ClassA;
class Base {
public: void Method(IObject * object) {}
};
class Derived : public Base {
public: void Method(ClassA * objet) {}
};
class IObject {};
class ClassA : public IObject {};
int main(int argc, char ** argv) {
IObject * object = new ClassA();
Derived derived;
derived.Method(object);
delete object;
return 0;
}
This doesn't compile because the compiler tries to use the Derived::Method version of the method, even though there exists a perfectly valid Base::Method for the given object.
To make this compile (and work), I need to add the following in Derived:
class Derived : public Base {
public:
// adding this line make the Base::Method visible to the compiler ??
using Base::Method;
void Method(ClassA * object) {}
};
After adding this line, everything works as intended.
What I don't understand is : why ? If I rename Base::Method to Base::BaseMethod, I can call it from the Derived instance without any problem. Why does the compiler fails to find the correct method based on the parameter's type ??
This rule is known as Function hiding in C++.
A method in derived class with same name as of the Base class method hides the base class method in derived class. The users of the derived class can only see the derived class method irrespective of the function parameter types. The base class method is simply not present in Derived class scope. So the overload resolution doesn't work as you expect it to.
To be able to access the Base class method in derived class you explicitly need to tell the compiler to bring it in the derived class scope with the using declaration.
This is called member function hiding: As soon as you have a function in a derived class having a different signature than a function with the same name in the base class, the base class versions of the functions are invisible to the derived class and its clients. Here's the reason why this was introduced.
I'm getting "hiding" warnings in my compiler because a class inherits from its parent has the same name but different parameters.
Adding a function that merely pushes out a warning to say that this function does nothing (as is true in the base class, but without the warning) that matches the parameters and name of the base class function to the derived class clears this compiler warning. What are the potential knock-on effects of this on the derived class?
EDIT: Assume that I do not wish them to be able to use the base class function. (Don't ask).
Redefining the name in the derived class effectively hides the function in the base class. That's what the warning tells you! :-)
It is a warning, because usually this is a mistake. If it is on purpose, that is ok (but very rare).
The inability of your users to access the base class function through a derived instance without explicitly writing out myDerivedObj.Base::foo(), which they're not likely to do.
Make your function signatures match up, instead, or change the function name.
You need to unhide the base class function in the derived class as:
using Base::Function;
Example:
class Base
{
public:
void Function(int) { cout << "Function(int)" << endl; }
};
class Derived : public Base
{
public:
using Base::Function; //NOTE THIS LINE : Unhiding base class function!
void Function(const char *) { cout << "Function(const char *)" << endl; }
};
Derived d;
d.Function(10); //this calls Base::Function
Demo : http://ideone.com/OTBxg
#include <iostream>
using namespace std;
class Duck {
public:
virtual void quack() = 0;
};
class BigDuck : public Duck {
public:
// void quack(); (uncommenting will make it compile)
};
void BigDuck::quack(){ cout << "BigDuckDuck::Quack\n"; }
int main() {
BigDuck b;
Duck *d = &b;
d->quack();
}
The code above doesn't compile. However, when I declare the virtual function
in the subclass, then it compiles fine.
If the compiler already has the signature of the function that the subclass will override, then why is a redeclaration required?
Any insights?
The redeclaration is needed because:
The standard says so.
It makes the compiler's work easier by not climbing up the hierarchy to check if such function exists.
You might want to declare it lower in the hierarchy.
In order to instantiate the class the compiler must know that this object is concrete.
If you change:
virtual void quack() = 0;
to
virtual void quack();
It will compile without implementing quack() in HugeDuck.
the = 0; at the end of the function declaration is essentially saying that all BigDucks will quack, but that it has to be implemented by each derived duck. By removing the = 0; the BigDuck quack will get called unless you implement quack in HugeDuck.
EDIT: To clarify the = 0; is saying that the derived class will have the definition for the function. In your example it is expecting HugeDuck to define quack(), but as you have it commented it out it does not.
As a side note, since all ducks can quack perhaps your original Duck class that we can not see should implement quack() instead?
Because C++ separates 'declaration' from 'polymorphism': any function needs a declaration for the compiler, regardless if it's virtual or not.
Your example doesn't go far enough, it has the 'abstract class' problem: a BigDuck cannot be instantiated because it has no implementation of quack in it's interface.
Generalizing the problem, we can declare the base function not pure virtual:
class Duck { public: virtual void quack(){} };
class BigDuck : public Duck {};
// WRONG: undeclared method definition
void BigDuck::quack(){ cout << "QUACK!"; }
In here, the compiler will complain that it has a symbol BigDuck::quack that wasn't declared. This has nothing to do with abstract classes or anything.
(Note: gcc says:
error: no 'void BigDuck::q()' member function declared in class 'BigDuck'
)
The definition of Quack() in your base class is "abstract" - it has no implementation. This tells the compiler that your derived class must implement it. Failure to do so is a compilation error.
BigDuck could be another abstract class and you might not want to implement quack until you get to the base class ReallyBigDuck.
Until you provide an implementation, all classes that inherit from a class that contains Pure Virtual Function are abstract - they cannot be instantiated. In order to provide such an implementation, you must declare the function in the class.
Declaring the methods in each classes will tell the compiler that class provides the different implementation for the method.
Also,
in case you want to create the objects of BigDuck on stack then how will compiler should know the signature of quack().
BigDuck aDuck;
aDuck.quack();