So heres my code:
#include <iostream>
class cBase
{
public:
void vf(int)
{
std::cout << "cBase\n";
}
};
class cDerived : public cBase
{
public:
void vf(int)
{
std::cout << "cDerived\n";
}
};
int main()
{
cBase b;
cDerived d;
b.vf(0);
d.vf(0);
}
This example hides the function vf() of the base class and calls the vf() function of the derived class. Heres another piece of code:
#include <iostream>
class cBase
{
public:
virtual void vf(int)
{
std::cout << "cBase\n";
}
};
class cDerived : public cBase
{
public:
void vf(int)
{
std::cout << "cDerived\n";
}
};
int main()
{
cBase b;
cDerived d;
b.vf(0);
d.vf(0);
}
Now, the vf() function of the derived class overrides the vf() function of the vase class.
So my question is: what is the point of virtual functions if i can achieve the same result with the default hiding mechanism of c++? Am i missing something here? Thanks in advance!
To make polymorphism work you need to work on pointers or references. When you use dot operator on object that is neither pointer or reference then virtual table is not used to call proper virtual function.
To see how it works, create derived object dynamically, assign it to base class pointer and call your function on it. This will call implementation from your derived class.
virtual functions give run time polymorphism. Your objects will not exhibit run time polymorphism which is when the same code using the same compile-time types can exhibit different behaviour based on the run time types of the objects in question. E.g:
void f(CBase& x) {
x.vf(0);
}
Without vf being virtual in CBase, the CBase::vf will be called even if the run time type of x is CDerived.
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.
I have a base class which serves as an interface (if I use that word correctly). The idea is that the base class has some derived classes that implement one virtual function of the base class. Then I also need another class that extends the base class (lets call it extended base). What I would like is that I can store a class derived from base into an extended base pointer.
MWE:
class Base {
public:
virtual ~Base();
virtual double value();
}
class Derived : public Base{
public:
double value() override {return 5;}
}
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase ();
virtual double value2(){return 10;}
}
int main() {
ExtendedBase * object;
object = new Derived();
std::cout << object->value(); //should give implementation in Derived, i.e. 5
std::cout << object->value2(); //should give implementation in ExtendedBase, i.e. 10
delete object;
return 0;
}
With this MWE I get a compile error at the second line in the main. error: cannot convert 'Derived*' to 'ExtendedBase*' in assignment object = new Derived();. Part of me understands why it doesn't work (although I can't explain), but I would like to know if I can get the desired behaviour in some other way.
P.S. Sorry about the bad question name, I couldn't think of another way to keep it short
P.S.2 I know raw pointers like this are not advised. In the future I will change to smart pointers but I don't think they are needed for this simple example
ExtendedBase and Derived are each derived from Base. If you want to use an ExtendedBase* pointer to point to a Derived object, you will need to derive Derived from ExtendedBase.
To use a different example,
class Feline{
virtual void run();
}
class Housecat : Feline{
void run() {}
}
class BigCat : Feline{
virtual void run();
virtual void roar();
}
Here Feline, Housecat, and BigCat are analogous to Base, Derived, and ExtendedBase. BigCat and Housecat are each Feline, but since Housecat is not a BigCat, you can't use a BigCat* pointer to point to a Housecat.
This is the desired behavior from a language architect perspective.
For instance, if you have
class Ship
{
public:
virtual void move() = 0;
}
class Steamboat : public Ship
{
public:
virtual void move() override { ... }
}
class Sailboat : public Ship
{
public:
virtual void move() override { ... }
virtual void setSails() { ... }
}
Now, you don't want a Steamboat to become a Sailboat all of a sudden, hence:
Steamboat* tootoo = new Sailboat;
cannot be valid.
That's why your code cannot work. Conceptually.
So giving a quick fix is not possible, because your concept is not really clear.
When you are assigning an address to a pointer that means you should be able to access all the members of the type the pointer is pointing to through the pointer.
For ex,
class B {};
class D : B {};
B *p = new D();
now through p, at least you can access all the members of base portion of the derived class.
But in your code,
ExtendedBase * object;
object = new Derived();
object should be able to access all the members of ExtendedBase portion of the derived class. But how is it possible as derived class is not derived from ExtendeBase. So compiler is throwing error.
You need to do some changes in your code to work.
To make base as interface (abstract class), you need to define at
least one member function as pure virtual.
If you want to access the member function of ExtendedBase through
Base pointer, you should define same function 'val' in your
ExtendedBase.
Below are the changes.
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {};
virtual double value() = 0;
};
class Derived : public Base{
public:
~Derived() {};
double value() {
return 5;
}
};
class ExtendedBase : public Base {
public:
virtual ~ExtendedBase () {};
double value()
{
return 10;
}
};
int main() {
Base *p = new Derived();
std::cout << p->value() << std::endl;
delete p;
Base *p1 = new ExtendedBase();
std::cout << p1->value() << std::endl;
delete p1;
return 0;
}
i do not understand why this behavior occurs:
class Base
{
public:
virtual void enablePolymorphism();
};
class Derived : public Base
{
public:
void enablePolymorphism();
};
class Derived2 : public Base
{
public:
void enablePolymorphism();
};
void callMe(Base base)
{
printf("base");
}
void callMe(Derived derived)
{
printf("derived");
}
void callMe(Derived2 derived2)
{
printf("derived2");
}
int main()
{
Base* pointer = new Derived();
Base* pointer2 = new Derived2();
callMe(*pointer);
callMe(*pointer2);
return 0;
}
this is what i actually want my code to do and i want the method callMe() to be outside the classes therefore i cannot use virtual functions, i want at run-time for the program to call callMe(Derived derived) when i do callMe(*pointer) and callMe(Derived2 derived2) when i do callMe(*pointer2) for which the output would be derivedderived2 but that's not what happens, at compile-time pointer and pointer2 are assumed to be of Base class when dereferenced so the callMe(Base base) is called instead and the output is basebase. How do i achieve the output i want? thank you.
void callMe(A);
void callMe(B);
A*ptr;
callMe(*ptr); // guess which of the above is called?
this has nothing to do with polymorphism, but is simple overloading resolution.
Runtime polymorphism applies only to member functions that are marked with the virtual keyword (or that override a virtual member function):
virtual void callMe();
For a non-member function, or a non-virtual member function, the appropriate overload is selected at compile time based on the declared type (not the runtime type) of the argument(s).
The only thing the compiler sees is that the expression *pointer is of type Base& and therefore succeeds into choosing the correct overload callMe(Base) for the function.
In your case, you can use a polymorphic function instead:
#include <memory>
#include <iostream>
class Base {
public:
virtual void callMe() { std::cout << "called base"; }
};
class Derived : public Base {
public:
virtual void callMe() { std::cout << "called derived"; }
};
int main() {
std::unique_ptr<Base> pointer(new Derived());
pointer->callMe();
return 0;
}
And here is the live example.
Starting from this code:
class Base{
public:
virtual void foo(){....}
};
class Derived{
public:
void foo(){....}
};
If d is a Derived object, can I in some way invoke the foo method defined in the Base class for this object?
Edit: i mean from the outside, such that d.foo() binds to Base::foo()
Specify it explicitly in the call.
#include <iostream>
class Base{
public:
virtual void foo(){
std::cout << "Base" << std::endl;
}
};
class Derived : public Base{
public:
void foo(){
std::cout << "Derived" << std::endl;
}
};
int main()
{
Derived d;
d.Base::foo();
return 0;
}
Just qualify the call (Assuming that Derived actually inherits from Base, which in your code it doesn't):
Derived d;
d.Base::foo();
Now, while this is doable, it is also quite questionable. If the method is virtual, it is meant to be overridden and users should not call a particular override, but the final-overrider, or else they risk breaking class invariants all the way through.
Consider that the implementation of Derived::foo did some extra work needed to hold some invariant, if users call Base::foo that extra work would not be done and the invariant is broken, leaving the object in an invalid state.
To call it from outside code, you can still explicitly qualify the name in the call:
#include <iostream>
#include <vector>
struct base {
virtual void do_something() { std::cout << "Base::do_something();\n"; }
};
struct derived : public base {
virtual void do_something() { std::cout << "derived::do_something();\n"; }
};
int main() {
derived d;
d.base::do_something();
return 0;
}
If you're using a pointer to the object, you'd change that to d->base::do_something();.
Sample code
#include <iostream>
using namespace std;
class Base
{
public:
virtual void Func()
{
cout << "\nIn base func";
}
};
class Derived : public Base
{
public:
void Func()
{
cout << "\nIn derived";
}
};
class Derived2 : public Derived
{
public:
void Func()
{
cout << "\nIn derived2";
}
};
int main()
{
Base* lnewbase = new Derived2();
lnewbase->Func();
return 0;
}
As an example, in the above code, I do not want Func() of Derived to be inherited (seal in C#) which is why there is no virtual keyword although I am aware that it does not change anything in this case. Is there any way to disallow that function to be inherited while making sure it remains a public method?
No; C++ has no equivalent to C#'s sealed modifier.
There is nothing you can do.
Once you make a function in a base class virtual, there's nothing that can be done to get rid of that aspect of it. I can only think of a few things to almost get around it:
Don't make it virtual;
Make a new, public, non-virtual function in Derived that does what you need.
However, in either case, Derived2 will still be able to make its own version of Func(), which will give you the same problem.