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.
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.
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.
I have problem with subclassing and using methods.
I create an instance of class B and store it as a pointer to A. But when I use the pointer to call the overloaded method, the output is "A" not "B". Why?
This works in other languages, what am I doing wrong?
#include <iostream>
using namespace std;
class A {
public:
void f() {
cout << "A";
}
};
class B : public A {
public:
void f() {
cout << "B";
}
};
int main() {
A *a = new B();
a->f();
return 0;
}
f() needs to be declared virtual in the base class A:
class A {
public:
virtual void f() {
cout << "A";
}
};
The other languages you already worked with may default to virtual methods, but C++ doesn't (don't pay for what you don't use: virtual methods incur an indirection when calling them which means they are slightly slower than normal method calls).
By adding virtual, binding will be postponed to runtime (called dynamic binding) and which f() function call will be decided on the type of the value.
Because you have not declared function f() as virtual, binding is static (at compilation time) and will use the type of variable (but not value) to determine which f() to call. So in your present code statment a->f(); calls the A class's f() because a is pointer to the A class.
In order to achieve polymorphic behavior, the method of the base class must be virtual.
So in class A you need to change void f() to virtual void f().
The function must be declared virtual to be able to override it:
#include <iostream>
using namespace std;
class A {
public:
virtual void f() {// Here you must define the virtual.
cout << "A";
}
};
class B : public A {
public:
virtual void f() { //Here the "virtual" is optional, but a good practice
cout << "B";
}
};
int main() {
A *a = new B();
a->f();
return 0;
}
You may face this problem when having not a pointers to the base class, but the actual instances of it (not applicable to the example in this question)
In my case, I had a class Token and its subclass Word:
class Token {
public: virtual string toString() { ... }
}
class Word: public Token {
public: string toString() { ... }
}
Storing them in std::map<string, Token> and retrieving from it I expected to call Word::toString() in code like this:
std::map<string, Token> words;
words.insert("test", Word(...));
words["test"].toString();
instead I called Token::toString() every time.
Solution: to use pointers like this std::map<string, Token*> and treat all instances as pointers
(TBH, I hate pointers already)
In C++, is it possible to require a method in a base class to be overridden by all of its derived classes without making it a pure virtual method?
#include <iostream>
using namespace std;
class BaseClass{
public:
int printStuff(){ //find some way to require all derived classes to override this method
cout << "Printing some stuff";
}
};
class DerivedClass: public BaseClass{
};
int main(){
cout << "Hello World!";
return 0;
}
I know you said you didn't want to use pure virtual functions, but you can use pure virtual functions and still give the method a definition if that's what you are trying to do (not sure if you knew that already):
class BaseClass{
public:
virtual int printStuff() = 0;
};
// give the pure virtual function an implementation
int BaseClass::printStuff() {
cout << "Printing some stuff";
}
class DerivedClass: public BaseClass{
// compiler error; DerivedClass must override printStuff
};
class DerivedClass2: public BaseClass{
public:
int printStuff() {
return BaseClass::printStuff(); // use the base class's implementation
}
};
It depends on what you mean by require. Usually "require" would mean "fails to compile unless it is done". If that is what you want, then pure virtual is the only want to define the method to achieve that. If you mean, "program won't work unless it is done", then you can provide a default implementation for a virtual method that does gives notice to the user that the implementation is missing.
class BaseClass {
protected:
virtual int printStuff () {
std::cout << "Nothing to print, please override printStuff()."
<< std::endl;
return -1;
}
};
When an implementation for a virtual method is provided (that is, the virtual method is not declared with an assignment of 0), it is no longer "pure". So this technique satisfies your "not a pure virtual method" requirement, but it is still a virtual method.
I am assuming you want this because you believe some part of your code needs to instantiate a plain BaseClass. If that is the case, you may consider partitioning BaseClass into two parts. One that is the "pure" interface, the other that has the stuff you are actually going to use when you instantiate it.
class BaseObject {
//...
};
class BaseClass {
protected:
BaseObject base;
virtual int printStuff () = 0;
};
So you would instantiate a BaseObject rather than a BaseClass.
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();.