Access overriden parent virtual method in C++ - c++

In the following code, how can I access Base::g() from pBase? (and still get "pBase->g();" to work as it does below)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f(){ cout << "Base::f()" << endl; }
virtual void g(){ cout << "Base::g()" << endl; }
void h(){ cout << "Base::h()" << endl; }
};
class Derived : public Base
{
public:
void f(){ cout << "Derived::f()" << endl; }
virtual void g(){ cout << "Derived::g()" << endl; }
void h(){ cout << "Derived::h()" << endl; }
};
int main()
{
Base *pBase = new Derived;
pBase->f();
pBase->g();
pBase->h();
Derived *pDerived = new Derived;
pDerived->f();
pDerived->g();
pDerived->h();
return 0;
}
Output is:
Derived::f()
Derived::g()
Base::h()
Derived::f()
Derived::g()
Derived::h()
Also, is Derived::f() exactly the same as Derived::g()? (ie. automatically defined as virtual?)

Use pBase->Base::g(); to force the call of g in Base.
Yes, Derived::f is virtual. I personally find the re-emphasising of virtual to be in poor taste. Since C++11, you can use the override specifier on overridden functions, and then a compiler issues a diagnostic if virtual is dropped from the base class.

Related

clang-diagnostic-error - allocating an object of abstract class type 'Base'

#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
virtual void foo() = 0;
protected:
int num{ 1 };
public:
Base() {
cout << "Base class constructor" << endl;
}
virtual ~Base()
{
cout << "Base class destructor " << endl;
}
private:
};
class Derive : public Base {
public:
Derive() {
cout << "Derive class constructor" << endl;
}
~Derive() {
cout << "Derive class destructor " << endl;
}
public:
void foo() override{
cout << "Derive class Foo function" << endl;
}
};
int main() {
unique_ptr<Base> b = make_unique<Base>(new Derive());
b->foo();
}
I get below error when I build this code.
in instantiation of function template specialization 'std::make_unique<Base, Derive *>' requested here unique_ptr b = make_unique(new Derive());
unimplemented pure virtual method 'foo' in 'Base' virtual void foo() = 0;
Does anyone know what is the reason of this error?
Note: I tried on https://godbolt.org/ and selected clang 11
In your main() function, do this instead:
unique_ptr<Base> b(new Derive());
This is because std::make_unique() takes the actual constructor arguments. You can't do that with polymorphism, but there's nothing wrong with directly instanstiating a std::unique_ptr directly with a heap allocated resource.
Do prefer std::make_unique() where it makes sense, though. This just isn't one of those cases.

Which vtable does the object of subtype use in c++

when I want to execute this line of code, it doesn't compile
baseArray[1]->function5();
But in vtable of Derived 3, function5 should points to function5 in Derived1. so I think it should output Derived1::function5(). But it seems to find function5() in the Base class
I just wondering that Derived3 inherited from Derived1, why it still check if the called function exists in Base class?
Please refer to the following code.
Thank you for your help!
#include <iostream>
using namespace std;
class Base {
public:
virtual void function1();
virtual void function2();
virtual void function3() = 0;
void function4();
};
class Derived1 : public Base {
public:
void function1();
virtual void function5();
void function6();
};
class Derived2 : public Base {
public:
void function2();
void function3();
void function4();
void function5();
};
class Derived3 : public Derived1 {
public:
void function3();
};
void Base::function1(){
cout << "Base::function1()" << endl;
}
void Base::function2(){
cout << "Base::function2()" << endl;
}
void Base::function4(){
cout << "Base::function4()" << endl;
}
void Derived1::function1(){
cout << "Derived1::function1()" << endl;
}
void Derived1::function5(){
cout << "Derived1::function5()" << endl;
}
void Derived1::function6(){
cout << "Derived1::function6()" << endl;
}
void Derived2::function2(){
cout << "Derived2::function2()" << endl;
}
void Derived2::function3(){
cout << "Derived2::function3()" << endl;
}
void Derived2::function4(){
cout << "Derived2::function4()" << endl;
}
void Derived2::function5(){
cout << "Derived2::function5()" << endl;
}
void Derived3::function3(){
cout << "Derived3::function3()" << endl;
}
int main(){
Base *baseArray[] = { new Derived2, new Derived3 };
baseArray[1]->function5(); //why the code doesn't compile when I call function5() here?
//in vtable of Derived 3, function5 should points to function5 in Derived1
//so I think it should output Derived1::function5()
dynamic_cast<Derived3*>(baseArray[1])->function5();
baseArray[1]->function6(); //same question, why it doesn't call function6 in Derived1?
//which vtable does baseArray[1] use?
dynamic_cast<Derived3*>(baseArray[1])->function6();
}
C++ is a statically typed language. That means references to types, members, variables, etc have to be known at compile-time.
The reason why baseArray[1]->function5(); and baseArray[1]->function6(); do not compile is because baseArray[1] is declared as a Base* but function5() and function6() are not members of Base. Simple as that. This has nothing to do with vtables. That is just an implementation detail of how compilers may choose to implement the dispatching of virtual method calls at runtime, but this is not required by the C++ standard.
The compiler doesn’t know that the Base* pointer is actually pointing at a Derived3 object. That fact is not determined until runtime. This is a key feature of polymorphism.
To call function5() and function6() correctly, you will need to type-cast the Base* pointer to a derived type that has the member you want to access, as you have already discovered. Note that dynamic_cast on a pointer will return nullptr if the cast fails, which you are not checking for, eg:
// Derived1 and Derived2 are not related, but each has its own function5()...
if (Derived1 *d1 = dynamic_cast<Derived1*>(baseArray[index]))
d1->function5();
else if (Derived2 *d2 = dynamic_cast<Derived2*>(baseArray[index]))
d2->function5();
On the other hand, if you know the exact and correct type up front (as in your example), you can use static_cast instead, eg:
static_cast<Derived1*>(baseArray[index])->function5();

C++ virtual function call by value

I attempt to modify the vfptr of a Base object to point to vtable which class Derived owns:
#include<iostream>
using namespace std;
class Base {
public:
virtual void func() { cout << "Base::func()" << endl; }
Base() = default;
Base(const Base&);
};
Base::Base(const Base&b) {
*((int*)(this)) = *((int*)(&b)); //modify the vfptr
}
class Derived : public Base {
public:
virtual void func() { cout << "Derived::func()" << endl; }
};
int main() {
Derived d;
cout << "Derived's vtable: " << *(int*)&d << endl << endl;
Base b = d;
cout << "Base's vtable: " << *(int*)&b << endl << endl;
cout << "pass by value:" << endl;
b.func();
cout << endl;
Base *bp = &b;
cout << "pass by pointer" << endl;
bp->func();
}
Output in VS2017:
Derived's vtable: 9739088
Base's vtable: 9739088
pass by value:
Base::func()
pass by pointer
Derived::func()
We can see that vfptr of object b does point to the Derived vtable after modifing but still call the Base version func() by value.
I wonder if the compiler handles such value-call by static binding even if what is called is a virtual function?
Thank you so much.
I wonder if the compiler handles such value-call by static binding
Base b = d;
b.func();
Yes, it does do static binding here indeed. In fact, using dynamic binding would be pointless because the dynamic type of the object is known to be the same as the static type at compile time.

C++ - const keyword in methods and overload

for which reason this program:
#include <iostream>
using namespace std;
class Base {
public:
Base() { cout << "Costruttore Base" << endl; }
virtual void foo(int) { cout << "Base::foo(int)" << endl; }
virtual void bar(int) { cout << "Base::bar(int)" << endl; }
virtual void bar(double) { cout << "Base::bar(double)" << endl; }
virtual ~Base() { cout << "Distruttore Base" << endl; }
};
class Derived : public Base {
public:
Derived() { cout << "Costruttore Derived" << endl; }
void foo(int) { cout << "Derived::foo(int)" << endl; }
void bar(int) const { cout << "Derived::bar(int)" << endl; }
void bar(double) const { cout << "Derived::bar(double) const" << endl; }
~Derived() { cout << "Distruttore Derived" << endl; }
};
int main() {
Derived derived;
Base base;
Base& base_ref = base;
Base* base_ptr = &derived;
Derived* derived_ptr = &derived;
cout << "=== 1 ===" << endl;
base_ptr->foo(12.0);
base_ref.foo(7);
base_ptr->bar(1.0);
derived_ptr->bar(1.0);
derived.bar(2);
return 0;
}
In the call base_ptr->bar(1.0); is called Base::bar(double), instead in the derived_ptr->bar(1.0); is called Derived::bar(double) const.
I understood that is about the const keyword, but I don't understand why the compiler is choosing different overloaded functions.
If I remove the const keyword, everything is working as expected, calling in both cases the Derived::bar
That's because const changes the signature of the function, so they're different. Either make both the base class and derived class const or not, otherwise one won't override the other.
It's because you're not really overriding the function bar(). You are defining a new function bar() in the derived class with a different signature.
So either remove the const in the derived class or add a const to the signature of bar() in the upper class. (Or keep it as it is but know that you now have two functions named bar() in derived class, one of which is hidden)
C++11 added the override specifier to prevent these kind of surprises. Use, the override keyword, and the compiler will only compile your code, if it does override.
Taking the supposedly override of bar(int) (this also applies to the bar(double):
class Base {
public:
....
virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};
class Derived : public Base {
public:
...
//This isn't an override, program is well formed
void bar(int) const { cout << "Derived::bar(int)" << endl; }
};
The bar member function in Derived did not override the base class' own. Because the const qualifications are different, hence the member function signatures are different. All you did in the derived class was to add a new overload and hide that of the base class'.
Add the override keyword in the derived class' and the compiler will give a diagnostic if it doesn't override.
class Base {
public:
....
virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};
class Derived : public Base {
public:
...
//This isn't an override, program is ill-formed, diagnostic required
void bar(int) const override { cout << "Derived::bar(int)" << endl; }
};
To override, the member function signatures must be the same.
class Base {
public:
....
virtual void bar(int) { cout << "Base::bar(int)" << endl; }
};
class Derived : public Base {
public:
...
//This overrides
void bar(int) override { cout << "Derived::bar(int)" << endl; }
};
So, learn to use the override keyword whenever you want to override, it will save you some headaches.

Why do I have to implement a virtual function in a derived class if I want to use the base class implementation

I have an pure virtual base class and a derived class. I know I am allowed to implement a virtual (not pure) method in the base class.
What I do not understand is why I HAVE to also implement the same method in the derived class if what I want is simply to use the base implementation:
#include <iostream>
using namespace std;
class Abstract {
public:
int x;
Abstract(){
cout << "Abstract constructor" << endl;
x = 1;
}
virtual void foo() = 0;
virtual void bar(){
cout << "Abstract::bar" << endl;
}
};
class Derived : Abstract {
public:
int y;
Derived(int _y):Abstract(){
cout << "Derived constructor" << endl;
}
virtual void foo(){
cout << "Derived::foo" << endl;
}
virtual void bar(){
Abstract::bar();
}
};
int main()
{
cout << "Hello World" << endl;
Derived derived(2);
derived.foo();
derived.bar(); //HERE I HAVE TO DEFINE Derived::bar to use it
return 0;
}
You don’t have to do that. You can do the following:
class Derived : public Abstract {
That way, you can use the public methods from the base class.