Calling base method however only second level base method exists - c++

Imagine a huge code base with many many inheritance. At some point a line comes in your way in the class you have to work with.
inherited::Load();
This is do what it says. It loads the base object into memory.
inherited is a typedef for the base class.
However the actual parent class does not have a Load method.
As a quick example:
class Base {
public:
Base() {};
void Load() {
cout << "Base ok" << endl;
}
};
class Derived : public Base {
public:
Derived() {};
};
class MostDerived : public Derived {
public:
MostDerived(){};
void Load() {
Derived::Load();
cout << "Child ok"<< endl;
}
};
Here, if we call MostDerived.Load() it will call its parent's Load method, but the Derived class doesn't have its own Load, only Base's Load method.
What is actually going on here? Why there is no compilation issue?
Is the Derived class copies all the method of the base, so it will have a Load method what is prints "Base ok"? Or does Derived simply calls forward the Base method?
I found a related question Do ALL virtual functions need to be implemented in derived classes? and the answer says
It inherits the bar implementation from its ancestor class.
For me it still miss leading that explicitly calling the Derived::Load() method works. However, there is only a Base::Load() method exists.

What is actually going on here? Why there is no compilation issue? Is the Derived class copies all the method of the base, so it will have a Load method what is prints "Base ok"?
Yes. A derived class inherits all methods from the base class. (yes really all of them, whether it can access them depends on the access specified for the methods).
For me it still miss leading that explicitly calling the Derived::Load() method works. However, there is only a Base::Load() method exists.
Sloppy speaking the Derived:: only tells the compiler to look for names accesible from Derived. As Derived does inherit from Base, it does have a Load method.
Maybe your confusion can be cleared up a bit by noting that Derived::Load indeed does refer to Base::Load:
#include <type_traits>
#include <iostream>
struct Base {
void Load() {}
};
struct Derived : Base {};
int main() {
std::cout << std::is_same_v< decltype(&Derived::Load), void (Derived::*) ()>;
std::cout << std::is_same_v< decltype(&Derived::Load), void (Base::*) ()>;
}
This prints 01, because Derived::Load is indeed a method of Base.
I hope the example is not adding confusion ;). It uses std::is_same to see if two types are the same. &Derived::Load gives me a member function pointer to the Load method in Derived whose type I infer via decltype. I compare that once to pointer to method of Derived and then to pointer to method of Base. It turns out that Derived::Load is a method of Base.

Related

Extend the existing C++ class

I'd like to add the extra functionality without changing the existing class.
Say,
class base{
public:
int i;
base(){i = 1;}
virtual void do_work(){ /*Do some work*/ }
};
If I want to add serialization member function to it, I will simply create a derived class
class derived : public base{
public:
void serialize();
};
void derived::serialize(){
cout << "derived class" << endl;
}
And I do need to handle existing base objects,e.g.
int main(){
base a;
derived & b = static_cast<derived &>(a);
b.serialize();
}
This example runs without problems. But I do know the downcast through static_cast is something to be avoided in general.
But I'd like to know if the downcast for this particular use case can be considered safe since the derived class only has one extra member function. Will it has some potential undefined behavior for accessing vtable?
The way you're extending Base you're not making use of the vtable because you have no virtual methods. It may be easier to think of it as Derived has A Base; That you created a new class that contains a Base member variable.
My Suggestion.
Template Function
I personally would go with a template function. You can keep all the work in your original question, and avoid the need of adding virtual calls to your class.
template<typename T>
void serialize_object(T& t)
{
t.serialize()
}
And then based on your example.
Derivied d;
serialize_object(d);
The big benefit is that you're not adding runtime cast here. The compiler will inform you if you pass an object that doesn't have a method serialize.
Go Virtual
If you really want to handle this through a virtual interface do so.
struct Serializable{
virtual void serialize()=0;
virtual ~Serializable(){}
}
class Derived : public Serializable {
public:
void serialize() override;
}
void Derivied::serialize()
{
std::cout << "Yah\n";
}
Then in your code.
Derivied d;
Serializable& s = dynamic_cast<Serializable&>(d);
However, the big concern here is who is the owner of your base class? Did they provide a virtual dtor? If not, then making use of std::unique_ptr or std::shared_ptr could cause you to not deal directly with the interface.
If you can write the serialize function in a derived class without touching private or protected members then you should simply make it a free function. That solves everything.
You can't just cast a base class object to an inherited class. Any members in the inherited class will not have been created and initialized. You need to start with an object of the inherited class.
You can go the other way, of course, and call base class functions from a function of a class inherited from the base, because the base class object will always be there as part of the inherited class object, by definition.
If you have a pointer to the base class, and you build with RTTI, you can use dynamic_cast to cast to an inherited class, but that cast will fail and return NULL if the object is not of the class you're trying to cast to. But usually it's better to call a virtual function than to use dynamic_cast.

Virtual function hiding in derived class

I have two classes related by inheritance:-
class Base
{
public:
virtual void f(int x)
{
cout << "BASE::int" << endl;
}
virtual void f(double x)
{
cout << "BASE::double" << endl;
}
};
class Derived : public Base
{
public:
virtual void f(str::string s)
{
cout << "DERIVED::string" << endl;
}
};
I have provided same method in derived class with different parameters. That means rather than overriding I am hiding base class versions of this function. So, below calls are expected and clear to me.
std::string str("Hello");
Base b;
b.f(1); //calls base class version.
b.f(str); //error.
Derived d;
d.f(1); //error.
d.f(str); //calls derived class version.
But I am not able get clarification for this last scenario.
Base *b = new Derived;
b->f(str); //results in error.
Would compiler not bind this call to derived version of f using vtables and vptrs. But instead it's doing something else. Can anyone provide me complete path how compiler would try to resolve this call as per language mechanisms.
If your pointer is of type Base* then you can only "see" members that are defined in class Base. The compiler doesn't (or pretends not to) "know" that the variable really points to an instance of Derived, even if you just assigned one to it on the previous line.
When you declare a variable to be of type Base*, you're telling the compiler: treat this as something that could point to a Base or to any class derived from it. So you can't access members that are defined in a particular derived class, because there's no guarantee that the pointer actually points to an instance of that derived class.
The vtable only enters the picture at runtime. The generated assembly would have a lookup of the vptr value for a function and a jump to that address. This also means that the polymorphism is "restricted" to functions that Base knows about. Note that this is what makes more sense as well - the definition of a class should only depend on itself and its parents. If you wanted to make Base* b aware of the virtual functions implemented by Derived, you would end up with the number of vtable entries in Bases depending on its children.

Difference between Superclass::method or this-> method

How and when would I call a super class method? Please referr to code segment for the two options:
class SuperClass {
public:
void method();
};
class SubClass : public SuperClass {
public:
void someOtherMethdo(){
this->method();
SuperClass::method();
}
};
using this->method() you call a function that is either implemented in your superclass, either by your own class.
When using superClass::method(), you make sure to call the one implemented by your parent.
#include <iostream>
#include <string>
class A {
public:
void func() {
std::cout << "A func" << std::endl;
}
};
class B : A {
public:
void func() {
std::cout << "B func" << std::endl;
}
void exec() {
this->func();
A::func();
}
};
int main() {
B b;
b.exec();
return 0;
}
This sample code will output
B func
A func
this->method();
...calls method on the derived class (and is the same as writing simply method();). This could call the inherited method from the parent (and does in the example), or it could call an overridden version in the child class (and will, if one exists).
SuperClass::method();
...will always call the method on the parent. This syntax is often used within an override in the child, when you want to keep and extend the functionality of the parent class method. E.g.
Class SubClass: public SuperClass {
//...
void method() {
SuperClass::method();
//...
}
};
Note that if you use the first syntax in this second case, you'll get recursion.
Note also that this has nothing to do with virtual methods. Marking a method as virtual means that, when the method is called via a base class pointer, the most-derived class method available will be called. In the code above, it makes no difference whether any of the methods are virtual since there are no base class pointers involved.
this->method
Will default to the local implementation in your derived class first, if that one isn't present, it will take the superclass method. If that one is not present it will give a compilation error.
superClass::method()
Will always direct to the method in your superclass
In most cases you want this->method. superClass::method() Is usefull when part of a method is implemented in the superclass and you want to extend it in the derived class. something like:
Class SubClass : public SuperClass {
public:
void someOtherMethdo(){
SuperClass::someOtherMethdo();
//Rest of the method
}
}
this->method() leaves room for ambiguity under certain circumstances (e.g. if more than one ancestor defines method with this signature), but at the same time allows method to be called no matter where exactly it is defined. If method is virtual it will call the most-derived version.
SuperClass::method() is explicit. It will either call that specific method or give a compiler error.
In this particular example, no difference.
If the method is virtual:
this->method() will call the function dynamically (call the top-most implemented version of the class)
SuperClass::method() results in a static call.
this->method(); call parent's in your case or if it's virtual - call the top of implemented functions in vtable. SuperClass::method(); will call parent's method.

C++ extend inherited functions

considering a simple inherited class:
class Base
{
void func() {
cout << "base" << endl;
}
};
class Derived : public Base
{
void func() {
cout << "derived" << endl;
}
};
if I run Derived::func() I get
derived
I would like to modify this code to get
base
derived
Something more similar to an extension than an overriding.
I've been able to get something similar with constructors, but not with normal functions.
Many thanks,
Lucio
class Derived : public Base
{
void func() {
Base::func(); // Call the base method before doing our own.
cout << "derived" << endl;
}
};
To access the base-class function from the derived class, you can simply use:
Base::func();
In your case, you would have this as the first line of the derived implementation of func().
Using Base::func(); is correct like a few others already stated.
Remember the constructor for the base class will always get called first, then the constructor for the derived class.
You've talked about constructor, a derived class's constructor will call base class's one, no matter whether you use an inherited constructor, it makes sense because a derived class should be able to construct the members inherited from the base class. And by default, constructor wouldn't be inherited.
But, the "normal" method goes the much different way.
First, please sure that in most of the time, it's not necessary for a method in derived class to call the same-name method in base class, and on the contrary, it will cover base class's one, although it did inherit it.
So if you really want to call base class one, you should tell complier explicitly. Using baseclass::somemethod will fulfill your request.
You can't do so.
You'll have to do like
Void derived:: func()
{
this->func(); /*you should use 'this pointer' to
access the base class functions*/
cout<<"derived";
}

Implicit upcasting question

I find when writing functions (that use function overloading) that accept either a main class or subclass argument, that often implicit upcasting will occur (the subclass is upcasted as the main class and the main class function called). I don't want this implicit upcasting to occur as it means subtle bugs sneak in and cause problems later on down the line.
I have searched on google for information on this, but there is little coherent information I can make use of and only indirect references to it.
How do I disable, stop or prevent implicit upcasting (and even downcasting) from occurring?
(I can't supply any example code as this is a general problem that occurs from time to time).
No, this isn't to do with methods (I would have specified methods) but functions.
No example code, but pseudo idea:
void Function(BaseClass &A);
void Function(SubclassClass &B);
Function(ASubclass); //Implicit upcasting occurs, calls BaseClass instead
The above situation won't happen conventionally (say that the SubclassClass function gets knocked out/erased), but Subclass will be upcast to the BaseClass for use with the BaseClass function, instead of, say, reporting an error or generating a warning - either would be helpful as I don't want implicit upcasting to occur.
Please don't confuse upcasting with non-virtual method calls.
class Base
{
};
class Derived1:public Base
{
};
class Derived2:private Base
{
};
void doSomething(Base *ptr)
{
}
int main()
{
Derived1 *ptr1 = new Derived1;
Derived2 *ptr2 = new Derived2;
doSomething(ptr1); //works fine
doSomething(ptr2); //Gives error
return 0;
};
Upcasting:
A Base class pointer can always point to a derived class object as long as the derived class is publically derived from the Base class. Eg: First Function Call.
This upcasting happens implicitly.
If the derivation is private this upcasting does not happen implicitly and compiler will issue an error.
Though, using private inheritance is not the way to achieve this behavior. You should use private inheritance if it suits your design and it will implicitly gaurantee you that upcasting never happens implicitly.
The "up-casting" you are talking about is normal. The symptoms you are describing sound like you are overloading a non-virtual parents member function.
For example
#include <iostream>
using namespace std;
struct A
{
void sayHello() {cout << "hello from A" << endl;}
};
struct B : public A
{
void sayHello() {cout << "hello from B" << endl;}
};
void hello(A& a)
{
a.sayHello();
}
int main()
{
A a;
B b;
hello(a);
hello(b);
}
will produce
hello from A
hello from A
but if you add the virual to A::sayHello everything works as you would expect
struct A
{
virtual void sayHello() {cout << "hello from A" << endl;}
};
I'm not 100% sure what's going on, but if base class methods are being called when you supply a derived-class object to a method with a base-class parameter type, then either a) you didn't override the base-class method in your derived class, or more likely b) you forget the 'virtual' keyword in your base-class declaration. Otherwise the derived-class method will be called as expected.
#Als your example wont work if derivation is in protected mode.Implicit upcasting is allowed within the derived class only (within methods of the derived class) because protected members can only be accessed inside the class that derives or base class.