A very similar question was asked here:
C++: Overriding a protected method which is called by another method
However, I would like to know how to override a callback function in a Base class so that another method can call the derived class's callback from the constructor rather than the Base class's callback.
I've given an example below:
#include <iostream>
class Base {
protected:
virtual void callback() {
std::cout << "Base" << std::endl;
}
public:
Base() {
callback();
}
};
class Derived : Base {
protected:
void callback() override {
std::cout << "Derived" << std::endl;
}
public:
// Use Base's constructor to call print
Derived() : Base() { }
};
int main() {
Base B;
Derived D;
return 0;
}
The output is:
Base
Base
but I would like the output to be:
Base
Derived
This cannot be done. You can see the explanation in this post.
The object is constructed from base - up. The base class gets constructed first and then the members of the derived class extend / override the base class. So when the base constructor is running, the members of the derived class don't exist yet, so you cannot call them.
Not sure what you need this for, but you can just call the same method again from the derived class and you should see the output of both calls (from base and from derived).
Related
Consider:
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo()\n"; };
};
class Derived : public Base
{
public:
void foo() override
{
std::cout << "Derived::foo()\n";
Base::foo();
}
};
int main()
{
Derived obj;
obj.foo();
return 0;
}
This is my code. Why can I call Base::foo() in the Derived class if I already redefined it in Derived class. Why doesn't the compiler delete Base::foo in class Derived after redefine?
"why compiler doesn't delete Base::foo in class Derived after redefine"
Because that isn't what virtual and override do. When you provide an override to a base class function, you do not replace it. You are defining a new version for that function. The base class's implementation continues to exist and to be accessible.
Consider the following code. Someone can still use a Base object, and the behaviour should not be changed because Derived exists. The output for base_obj.foo() should continue to be "Base::foo()" regardless of the existance of Derived. :
#include <iostream>
class Base
{
public:
virtual void foo() { std::cout << "Base::foo()\n"; }
};
class Derived : public Base
{
public:
void foo() override { std::cout << "Derived::foo()\n"; }
};
int main()
{
Derived obj;
obj.foo();
Base base_obj;
base_obj.foo();
return 0;
}
Also consider that multiple classes can derive from Base. I could add a class MyClass : public Base with its own version of foo(), and it should not interfere with how Base or Derived objects behave.
If overriding a member function would cause the base member function to be entirely replaced or removed, it becomes nearly impossible to reason about code without reading carefully every class that derives from it. And unless your IDE provides tools for that, it implies reading all of the code base. It would make it C++ code that uses polymorphism extremely difficult to understand.
Consider this code:
#include <iostream>
class Base
{
public:
void Message()
{
std::cout<<"You are calling the function of class Base ";
}
};
class Derived : public Base
{
public:
void Message()
{
std::cout<<"You are calling the function of class Derived ";
}
};
int main()
{
Derived obj1;
obj1.Base::Message();
return 0;
}
These two lines of code:
Derived obj1;
obj1.Base::Message();
Call the class Derived which is derived from Base. The second line of code calls the Base class overridden function Message.
Why does the standard introduce obj1.Base::Message() when we can directly call the function Message with this code?
Base obj1;
obj1.Message();
Base::Message is necessary if you want to call that function on an object of type Derived. In the particular example you give, it's true that an alternate way of doing this is to use static_cast<Base&>(derived).Message(). However, in the case that Message is a virtual function, this won't work--you would always get Message from the most derived class.
One place where this is often used is if you are overriding a virtual function, but want to call the base function from within the derived one. For example:
class Base
{
public:
virtual void Message()
{
std::cout<<"You are calling the function of class Base ";
}
};
class Derived : public Base
{
public:
void Message() override
{
Base::Message();
std::cout<<"(and now for the Derived-only part of the message)";
}
};
What is the derived class doing in this code like:
class Base
{
public:
virtual std::string Name(){ return "Base Class"}
};
class Derived : public Base
{
public:
std::string Name() {return "Derived Class"}
}
int main()
{
Base* object = new Derived();
return 0;
}
I was following a tutorial but didn't understand What does Derived class in The instantiation of Base Class was doing in the above code.
The goal is to implement polymorphism, it's a OOP concept which allows you, among other things, to make derived class methods override the base class.
Consider the following:
class Base {
public:
//virtual keyword allows method to be overriden
virtual std::string Name() { return "Base Class"; }
//virtual destructor needed for polymorphism otherwise it can lead to undefined behavior
virtual ~Base(){}
};
class Derived : public Base {
public:
//optional keyword override signal the method has been overriden
std::string Name() override { return "Derived Class"; }
};
class Derived2 : public Base {
public:
std::string Name() override { return "Derived Class 2"; }
};
int main() {
Base *object = new Derived();
Base *object2 = new Derived2();
Base *object3 = new Base();
//collection of objects of type Base* which can hold any class of the family
Base *collection[] = {object, object2, object3};
for (auto &obj : collection) {//test print
std::cout << obj->Name() << std::endl;
}
}
As the comments explain, I can have a collection of different objects of the same family and when you call Name() the method call will deppend on the object.
Output:
Derived Class
Derived Class 2
Base Class
modifying main to be :
int main()
{
Base* object = new Derived();
std::cout << object->Name() << std::endl;
return 0;
}
and adding 3 missing ';' in your code, you will see that writes Derived Class, the called method Name is the one of the real type of object being Derived.
Note while Name is virtual in Base it is also in Derived even you do not said explicitly.
virtual allows to use the real type of an object when you apply an method on, so even object is declared Base when Name is virtual the called version is the one of the real type being Derived
But if you remove virtual in the definition of Name in Base that writes Base Class because object being declared Base the called method is Name defined on Base.
The result will be the same adding virtual on Derived but still removing it on Base, because for the compiler object being declared Base and Name being not virtual on Base that one is called without considering the real type of object
So, having :
#include <iostream>
#include <string>
class Base
{
public:
virtual std::string virtualName(){ return "Base Class";}
std::string nonVirtualName(){ return "Base Class";}
};
class Derived : public Base
{
public:
std::string virtualName() {return "Derived Class";} // implicitely virtual
std::string nonVirtualName(){ return "Base Class";}
};
int main()
{
Base* object = new Derived();
std::cout << object->virtualName() << std::endl;
std::cout << object->nonVirtualName() << std::endl;
return 0;
}
Compilation and execution :
bruno#bruno-XPS-8300:/tmp$ g++ -Wall a.cc
bruno#bruno-XPS-8300:/tmp$ ./a.out
Derived Class
Base Class
bruno#bruno-XPS-8300:/tmp$
Note if you add delete object; at the end of main and because of the default destructor in not virtual the called destructor is the one of Base exactly for nonVirtualName and nothing is done for Derived. Defining the destructor virtual on Base is the right way to do, that implies the destructor is at least implicitly virtual on Derived allowing to have both destructors executed on delete object;
I have a situation similar to below (code is NOT exact, just to get my point across). When I call D.A() I expect the word "Desc" to be printed, but instead "Base" is printed.
class Base {
public:
void A() { B(); }
virtual void B() { cout << "Base"; }
}
class Descendant : public Base {
public:
virtual void B() overriden { cout << "Desc"; }
}
main () {
Descendant D;
D.A();
}
There must be something conceptual I'm missing here. Should D.A() cause "Desc" to be printed? If not, why?
There is an important error in the question. The method A is in fact the constructor of the Base class. And it makes sense that the constructor can't call any methods (even virtual) of derived classes since those derived classes don't exist yet.
When A is a non-ctor, it works as expected.
1.In the main function below, why does d.foo(9.5) not select the Base::foo(double) method from the base class? Doesn't the derived class inherit that method?
2.What causes the compile error?
class Base {
public:
virtual void foo(int){
cout << "Base::foo(int)" << endl;
}
virtual void foo(double){
cout << "Base::foo(double)" << endl;
}
};
class Derived : public Base {
public:
virtual void foo(int){
cout << "Derived::foo(int)" << endl;
}
};
void main() {
Derived d;
Base b, *pb = &d;
d.foo(9); // selects Derived::foo(int)
d.foo(9.5); // selects Derived::foo(int)
pb->foo(9); // selects Derived::foo(int)
pb->foo(9.5); // selects Base::foo(double)
Derived * d;
d->foo(9); // compile error
}
The compilation error is because of two variables with the same name in main().
As to your problem with inherited functions not being called for an instance of your Derived (except via pointer to Base)
The standard describes the "hiding rule", which makes this happen. Essentially, member functions declared in derived classes hide inherited functions with the same name but different signature inherited from the base class. The hiding rule is independent of whether the inherited functions are virtual or not.
The common solution is to introduce all inherited functions from the base class with using Base::foo. For example,
class Base {
public:
virtual void foo(int){
cout << "Base::foo(int)" << endl;
}
virtual void foo(double){
cout << "Base::foo(double)" << endl;
}
};
class Derived : public Base {
public:
using Base::foo;
virtual void foo(int){
cout << "Derived::foo(int)" << endl;
}
};
Another solution is to remember to explicitly override all inherited versions of the function (implement the derived class version to simply call the base class version of each function). This works with older compilers that do not support a using directive like the above. The catch is that it is necessary to explicitly do this with every inherited overload, and it is easy to miss one.
In the main function below, why does d.foo(9.5) not select the Base::foo(double) method from the base class? Doesn't the derived class inherit that method?
Yes, but it's hidden by the function with the same name in the derived class. You can unhide it with a using-declaration in the derived class:
using Base::foo;
What causes the compile error?
You're trying to declare a second variable called d. Change the name to something that's not already used; and initialise it to point to a valid object, otherwise you'll have a runtime error or other undefined behaviour.
Derived * pd = &d;
pd->foo(9); // selects Derived::foo(int)
Also, main has the wrong return type. It must return int.
1) Because this is exactly how polymorphism work. If a virtual function is redefined in a derived class, this (and only this) redefined version will be called. If the function is not virtual it's vice versa: only the base class function will be called.
//Example 1: non-virtual function
class Base
{
public:
void foo()
{
std::cout << "Base";
}
}
class Derived : public Base
{
public:
void foo()
{
std::cout << "Derived";
}
}
Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Base", since the function is not virtual, and the version from the base class is called
//Example 2: virtual function
class Base
{
public:
virtual void foo()
{
std::cout << "Base";
}
}
class Derived : public Base
{
public:
void foo()
{
std::cout << "Derived";
}
}
Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Derived", since the function is virtual, and the redefined version from Derived class is called
2) The compile error happens because you have a conflicting declaration - two objects are called d.
Derived * d;
d->foo(9); // compile error
You don't have instantiated the object:
Derived * d = new Derived;
If you not create the object the compiler use the previous declaration of d: Derived d that is not a pointer.