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().
Related
As far as I learned, Overriding is when you have 2 functions which have the same name and function return type (void, int, float.. etc) and the same parameter numbers and types.
And the overloading is when you have 2 functions which have the same name but either Parameter number/types or function return type should be different.
But today when I was in the class, I saw this slide:
Shouldn't this be overloading? Not overriding? Because here the return type changed (from void
to float) and fa1() function in the base class had no parameter, but in the derived class it has float parameter.
If this is overriding, why?
In C++, any method in a derived class only overrides the method in the base class if their declarations match (I say "match" but I don't know the formal term for that). That is, all arguments must have the same type, and const qualification of this must be the same. If anything there mismatches, the method in the derived class hides all methods with the same name, instead of overriding. This is what the "ERROR" in your picture tries to tell you. So // overrides in a comment in that picture is incorrect and misleading.
Yes, many C++ teachers actually don't understand these somewhat obscure details.
BTW additionally, if you want to override, the method in your base class should be virtual; otherwise, polymorphism won't work. If it was not virtual, we also say that the derived-class method hides the base-class method. Here, however, the part about hiding has almost no meaning; what this term really wants to express is that you're not overriding.
In addition, overloading is, as you noticed, presence of several methods with the same name but different signatures. They should all be present in the derived class to be useful - if the derived class has only one method fa1, and the other fa1 are in the base, they will be hidden. However, there is syntax sugar which "copies" all fa1 from base to derived, disabling all that hiding semantics:
class A
{
public:
void fa1();
void fa1(int);
};
class B: public A
{
public:
using A::fa1;
void fa1(int, int);
};
...
B b;
b.fa1(); // calls A::fa1()
b.fa1(4); // calls A::fa1(int)
b.fa1(4, 8); // calls B::fa1(int, int)
The part about hiding is rarely, if ever, useful. When overriding, you should tell this to your compiler - use the override keyword for that. The compiler will then check that your code works as you intended.
class A
{
public:
virtual void fa1(int) {}
void fa2(int) {}
};
class B: public A
{
public:
void fa1(int) override {} // OK
void fa1() override {} // ERROR: doesn't really override - different signature
void fa2(int) override {} // ERROR: doesn't really override - not virtual in base
};
ia1 not overloading. First you can't overload variables. So ia1 is definitely an override. And it's also a dangerous thing. At my company, our coding standards disallow overriding variable names in any situation. It just leads to confusion.
fa1 though -- that looks like an overload. The base class fa1() takes no arguments, but the subclass version takes a float.
I have a template method in a parent class, that should call another method from the base class. It works, if the method is explicitly defined in the base class, but it doesn't work if the method is inherited. I can't figure out what's exactly wrong with this code (although I know it's a little weird :)
class A
{
protected:
virtual void someMethod()
{
}
template <class TBaseClass>
void templateMethod()
{
TBaseClass::someMethod();
}
};
class B : public A
{
};
class C : public B
{
protected:
virtual void someMethod()
{
templateMethod<A>(); // this works
templateMethod<B>(); // this doesn't
}
};
This ends up with compiler error:
error C2352: 'A::someMethod' : illegal call of non-static member function
What exactly is wrong? I'm not looking for workarounds, that's easy. I'd like to know why is this incorrect.
In template <TBaseClass> void A::templateMethod() the invocant, this, is of type A *. So when you try to call B::someMethod on it, the compiler won't recognize it a object method call, because B is not a base class, but it can still be a static method call, so the compiler will try that, find B::someMethod inherited via A and complain it is not static. The fact that A is a base class of this is not relevant; only that B is not.
The issue is that class A is not automatically granted access to class B. The methods within the class don't know that the current instance of A is actually of type B.
To do what you're trying, you need to cast A to the target type:
template <class TBaseClass>
void templateMethod()
{
static_cast<TBaseClass*>(this)->someMethod();
}
This will work if the particular instance of A you're calling really is a B (as it is in the example you give). There is no type checking done here to be sure it is. If you pass a class that is not in the inheritance hierarchy you will be in the work of undefined behavior.
That said, your example has "someMethod()" as virtual. If you're doing what I just did here then making that method virtual may not make sense, as you are explicitly saying which instance you want. If you do leave it virtual, then just calling someMethod() directly in A will get you the most derived instance.
I think it's not working because you are trying to call a static method.
Static methods can be inherited but they can't be virtual.
Thats why A::someMethod will work and B::someMethod won"t work.
I have a virtual base class function which should never be used in a particular derived class. Is there a way to 'delete' it? I can of course just give it an empty definition but I would rather make its attempted use throw a compile-time error. The C++11 delete specifier seems like what I would want, but
class B
{
virtual void f();
};
class D : public B
{
virtual void f() = delete; //Error
};
won't compile; gcc, at least, explicitly won't let me delete a function that has a non-deleted base version. Is there another way to get the same functionality?
It is not allowed by the standard, however you could use one of the following two workarounds to get a similar behaviour.
The first would be to use using to change the visibility of the method to private, thus preventing others from using it. The problem with that solution is, that calling the method on a pointer of the super-class does not result in a compilation error.
class B
{
public:
virtual void f();
};
class D : public B
{
private:
using B::f;
};
The best solution I have found so far to get a compile-time error when calling Ds method is by using a static_assert with a generic struct that inherits from false_type. As long as noone ever calls the method, the struct stays undefied and the static_assert won't fail.
If the method is called however, the struct is defined and its value is false, so the static_assert fails.
If the method is not called, but you try to call it on a pointer of the super class, then Ds method is not defined and you get an undefined reference compilation error.
template <typename T>
struct fail : std::false_type
{
};
class B
{
public:
virtual void f()
{
}
};
class D : public B
{
public:
template<typename T = bool>
void
f()
{
static_assert (fail<T>::value, "Do not use!");
}
};
Another workaround would be to throw an exception when the method is used, but that would only throw up on run-time.
The standard does not allow you to delete any member of a base-class in a derived class for good reason:
Doing so breaks inheritance, specifically the "is-a" relationship.
For related reasons, it does not allow a derived class to define a function deleted in the base-class:
The hook is not any longer part of the base-class contract, and thus it stops you from relying on previous guarantees which no longer hold.
If you want to get tricky, you can force an error, but it will have to be link-time instead of compile-time:
Declare the member function but don't ever define it (This is not 100% guaranteed to work for virtual functions though).
Better also take a look at the GCC deprecated attribute for earlier warnings __attribute__ ((deprecated)).
For details and similar MS magic: C++ mark as deprecated
"I have a virtual base class function which should never be used in a particular derived class."
In some respects that is a contradiction. The whole point of virtual functions is to provide different implementations of the contract provided by the base class. What you are trying to do is break the contract. The C++ language is designed to prevent you from doing that. This is why it forces you to implement pure virtual functions when you instantiate an object. And that is why it won't let you delete part of the contract.
What is happening is a good thing. It is probably preventing you from implementing an inappropriate design choice.
However:
Sometimes it can be appropriate to have a blank implementation that does nothing:
void MyClass::my_virtual_function()
{
// nothing here
}
Or a blank implementation that returns a "failed" status:
bool MyClass::my_virtual_function()
{
return false;
}
It all depends what you are trying to do. Perhaps if you could give more information as to what you are trying to achieve someone can point you in the right direction.
EDIT
If you think about it, to avoid calling the function for a specific derived type, the caller would need to know what type it is calling. The whole point of calling a base class reference/pointer is that you don't know which derived type will receive the call.
What you can do is simply throwing an exception in the derived implementation. For example, the Java Collections framework does this quite excessively: When an update operation is performed on a collection that is immutable, the corresponding method simply throws an UnsupportedOperationException. You can do the same in C++.
Of course, this will show a malicious use of the function only at runtime; not at compile time. However, with virtual methods, you are unable to catch such errors at compile time anyway because of polymorphism. E.g.:
B* b = new D();
b.f();
Here, you store a D in a B* variable. So, even if there was a way to tell the compiler that you are not allowed to call f on a D, the compiler would be unable to report this error here, because it only sees B.
I have a virtual base class function which should never be used in a particular derived class.
C++11 provides a keyword final which prevents a virtual function being overriden from.
Look: http://en.cppreference.com/w/cpp/language/final .
class B
{
virtual void f() final;
};
class D : public B
{
// virtual void f(); // a compile-time error
// void f() override; // a compile-time error
void f(); // non-virtual function, it's ok
};
This question already has answers here:
What is an undefined reference/unresolved external symbol error and how do I fix it?
(39 answers)
Closed 8 years ago.
This is one of those cases where I thought I understood C++ virtual methods reasonably well, and then an example comes along where I realise that, sadly, I don't. Is there anyone reading this who can make sense of the following?
Here is some test code in which I define a very simple base class (actually just a two-element struct), an abstract template class containing a virtual void method, and then a derived class which inherits from both of them and explictly overrides the virtual void method with a concrete method.
#include <string.h> // For memcpy
#include <vector> // For std::vector
struct int_array_C
{
int n;
int* contents;
};
template <typename T> class array_template
{
public:
array_template<T>() {}
array_template<T>(const array_template<T> &source)
{
*p_n = *(source.p_n);
setPointers(&(source.local_contents[0]));
}
// ..and in reality, a bunch of other array manipulation functions
protected:
virtual void setPointers(const T* data) = 0;
int *p_n;
std::vector<T> local_contents;
};
class int_array : public int_array_C, public array_template<int>
{
public:
int_array() : array_template<int>()
{
n = 0; contents = NULL;
}
protected:
virtual void setPointers(const int* data)
{
p_n = &n;
local_contents.resize(n);
memcpy(static_cast<void *>(&local_contents[0]),
static_cast<const void *>(data), n*sizeof(int));
contents = &local_contents[0];
}
};
int main()
{
int_array myArray;
int_array yourArray(myArray);
return 1;
}
When the copy constructor is called in the second line of main(), the argument is an instance of the derived class which has a concrete setPointers() method. Therefore, when the template class's copy constructor is called and the call to setPointers() is encountered, I'd expect the rules of polymorphism to kick in and the derived class's setPointers() method to be called.
In fact, however, the compiler chokes on this; at compilation time I get a warning saying
"Warning: call of pure virtual function at line 18"
and at link time the linker fails with a message saying
error LNK2019: unresolved external symbol "protected: virtual void __cdecl array_template<int>::setPointers(int const *)" (?setPointers#?$array_template#H##MEAAXPEBH#Z) referenced in function "public: __cdecl array_template<int>::array_template<int>(class array_template<int> const &)" (??0?$array_template#H##QEAA#AEBV0##Z)
Exactly the same thing happens (with slight variation in the text of the error messages) using Visual C++ and Intel C++ on Windows and gcc on Linux, so it's obviously a genuine violation of language rules rather than just being a compiler quirk. Yet I can't see what the problem is.
So, what am I doing wrong and how might I make this work as intended?
In the execution of a constructor body for a class T the dynamic type is T. Any direct or indirect call of a pure virtual T member function here, is therefore invalid. It's some extra type checking security of C++, ensuring that you don't accidentally get into derived class code before the derived class sub-object has been properly initialized (or at least given the chance).
However, I don't understand why it ends up as a linking error.
Regarding solutions, this is a FAQ; essentially you have to somehow pass the derived class functionality or data up to the base class, and there are many ways to do that. As it happens I once convinced Marshall to include that FAQ item. So I can to some degree claim it as my answer to your problem. :-)
Update on the original code behavior.
Adding the following:
template< class T >
void array_template<T>::setPointers( const T* data )
{
using namespace std;
clog << "!pure virtual setPointers called!" << endl;
}
it turned out that with both Visual C++ 12.0 and g++ 4.8.2 it was called.
The call is Undefined Behavior so both compilers are in their right to produce such behavior, but still it surprised me. I'd think instead they would put a pointer to some error function in the vtable. Anyway, it explains the linking errors, with these two compilers.
Paul Griffiths nailed it with his comment under my original question:
"You can't call a derived class's virtual function from a base class constructor, because at the time it's called the derived class hasn't been constructed yet."
That's the critical thing: the call occurs in the constructor, and because the base class's constructor is called before the derived class exists, there is no concrete version of setPointers to call yet (at least, not in the new object that is in the process of being created; the fact that the old object being passed as an argument has one is irrelevant here).
The solution is pretty simple: move the copy constructor out of the template altogether and place it within the derived class instead. It's only a two-line function so it's not too painful to do this with each of my dozen or so derived classes, and it solves the problem.
[N.B. If anyone is wondering what all this is in aid of, this is part of a large mixed-language application. I want to have a set of container functions which have the functionality of a std::vector when used in C++, so that I can resize, reference, copy etc. at will, but then pass to a plain C subroutine expecting just the base struct. Everything except the template copy constructor has been working well for a long time now!]
You cannot call virtual methods from base class constructors and get derived class methods: those are set up after the base class is constructed.
Try changing the layout of your inheritsnce:
class int_array_impl:public int_array_C{...};
template<class T,class B>class array_template:public B{
//...
};
typedef array_template<int, int_array_impl> int_array;
make the method non-virtual, get rid of pure virtual stuff in array_template, and just blindlh invoke this->method. If B has it, it will be called.
Either forward constructors, or have a 4th class under array_template that provides custom ones.
I'm writing a little program in C++ and I what to play with polymorphism.
So the code goes like this:
//Base.h
class Base{
public:
void method(const objectType1& stuff1);
//objectType1 is whatever type you what (int, string, ...)
protected:
Base(void);
virtual ~Base(void);
virtual void method(void) = 0;
};
//Derived.h
/*FINAL - DO NOT INHERIT THIS CLASS OR YOU WILL die :)*/
class Derived : public Base{
public:
Derived(void);
~Derived(void);
private:
void method(void);
};
//Main.cpp
int main(){
objectType1 ot1;
//this code works
Base *bd = new Derived;
bd->method(ot1);
//this dosen't
Derived *dd = new Derived;
dd->method(ot1);
// he doesn't call Base::method(const objectType1& stuff1),
// he calls Derived::method(void)
return 0;
}
I've solved the problem by renaming the virtual method void method(void) in something else and all is well.
My questions are:
Why doesn't the compiler know to call the method from the base class?
And why do I see void method(void) in main since it is declared as protected in Base and private in Derived ? (is this some sort of side effect)
Thanks :) .
The member method in the base class is public, which means that any piece of code can call it. Besides being public, it is virtual, which means that the execution will be dynamically dispatched at runtime to the final overrider.
Access to the method is checked statically in the static type of the reference/pointer through which the call is dispatched, even if it will be dynamically dispatched.
On the other hand in the second case, the call is through the derived type, and the access specifier is checked at that level, where the compiler finds the member function to be private and thus complains.
In plain english, when the object is used as a base, it behaves as a base, but when used directly it behaves as derived.
The method definition in Derived hides the definition in Base. To avoid that, add using Base::method; to Derived.
This happens because when calling functions in Derived, the compiler looks into Base only if it didn't fine the name in Derived. Note that it doesn't look for the signature but only for the name in that stage. Overload resolution based on the signature is done only afterwards. This is actually not much different to the following situation:
void function(int);
void function();
int main()
{
void function(); // this declaration hides *both* global declarations
function(3); // error
}
In your case Base plays the role of the global scope and Derived the role of the function scope.
Also note that this is not related to virtaul fgunctions; indeed the same would happen without virtual (except that you then couldn't call Derived's method via a pointer to Base, of course, but would call the Base version instead).