I am having two problem about virtual methods.
First:
class Parent
{
public:
virtual void SHOW(int x = 5) { cout << "PARENT " << x << endl; }
};
class Child : public Parent
{
public:
virtual void SHOW(int y = 10) { cout << "CHILD " << y << endl; }
};
int main()
{
Child Y;
Parent* P = &Y;
P->SHOW();
getch();
return 0;
}
I think tt should be CHILD 10 but the result is CHILD 5
And another:
class Parent
{
public:
virtual void SHOW() { cout << "PARENT" << endl; }
};
class Child : public Parent
{
private:
virtual void SHOW() { cout << "CHILD" << endl; }
};
int main()
{
Child Y;
Parent* P = &Y;
P->SHOW();
getch();
return 0;
}
It'll show CHILD on the screen. I don't know how a private method which was called from outside?
Thank you. I'm learning English so.. :)
1)
C++ Standard says
A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default arguments from the function it overrides.
§8.3.6/10
2)
Overriding public virtual functions with private functions in C++
A virtual function call uses the default arguments in the declaration of the virtual function determined by the static type of the pointer you use to call the function. In your case the static type of P is Parent although the dynamic type resolves to Child. This is according to C++ standard.
This is a good example of why it is typically best to make virtual functions private and public functions non-virtual. Herb Sutter once called this the Non-Virtual Interface Idiom (NVI).
Let's apply it to your code. I'll also change the function name "SHOW" to "show", because all-uppercase in C++ usually denotes a macro. Furthermore, I'll add a virtual destructor, because newbies are reading these questions and they shouldn't see a polymorphic class without one. Note that destructors are an exception to NVI.
Here we go:
class Parent
{
public:
void show(int x = 5) { doShow(x); }
virtual ~Parent() {}
private:
virtual void doShow(int x) { cout << "PARENT " << x << endl; }
};
class Child : public Parent
{
private:
virtual void doShow(int x) { cout << "CHILD " << x << endl; }
};
Default arguments are usually useful for code which uses the objects of a class. That code then uses the public functions.
Parent *p = new Child;
p->show(); // here's where a default argument is a useful feature
delete p;
Inheriting classes, however, are interested in something completely different, namely in the virtual functions of the base class. It turns out that you rarely feel the need for default arguments when you write the code for a subclass.
Bottom line:
Default arguments and virtual functions shouldn't be mixed. There is an item for this in the famous Effective C++ book by Scott Meyers: "Never redefine an inherited default parameter value". You should read that book.
Using NVI, you will typically not have this problem anyway, because it turns out default arguments are more of a thing for public functions, and with NVI, public functions aren't virtual.
Related
Is there some way that I can make sure that the base classes function is called from the overridden function in the child class.
Example:
#include <iostream>
class Base
{
public:
virtual void func()
{
std::cout << "Really important code was ran" << std::endl;
}
};
class ChildExplicit : public Base
{
void func() override
{
Base::func();
std::cout << "child class explicitly calling Base::func" << std::endl;
}
};
class ChildImplicit : public Base
{
void func() override
{
std::cout << "child not explicitly calling Base::func" << std::endl;
}
};
int main()
{
Base* explicitChild = new ChildExplicit();
Base* implicitChild = new ChildImplicit();
explicitChild->func();
std::cout << std::endl;
implicitChild->func();
}
This should either output this:
Really important code was ran
child class explicitly calling Base::func
Really important code was ran
child not explicitly calling Base::func
or yield some kind of error that Base::func was not called in ChildImplicit::func.
One solution that would be possible is to make func non virtual and creating a second protected function that will be called in Base::func, the child classes would then override the protected function. But as you can imagine if apply this to a Base class of the Base class of the Base class scenario and each of there implementations must be called this gets quite messy. Would there be an other way to achieve the same goal?
I come from a Python background, and currently I'm learning OOP in C++.
I'm having problems figuring out how to get the code to call the correct method in a helper class HelperBase that is inherited to HelperChild.
#include <iostream>
class HelperBase {
public:
HelperBase() {}
virtual void something() {
std::cout << "HelperBase" << std::endl;
}
};
class HelperChild : public HelperBase {
public:
HelperChild() {}
void something() {
std::cout << "HelperChild" << std::endl;
}
};
The HelperBase class i used in the class Base, where it is set as a member variable.
class Base {
public:
Base(HelperBase &helperBase) : hb(helperBase) {}
virtual void print() {
std::cout << "-- Base" << std::endl;
hb.something();
}
HelperBase hb;
};
Then this class is used as the base class of the class Child:
class Child : public Base {
public:
Child(HelperChild &helperChild) : Base(helperChild) {
helperChild.something();
}
};
The main method is
int main() {
HelperChild helperChild;
Child child(helperChild);
child.print();
return 0;
}
This outputs the following:
HelperChild
-- Base
HelperBase
Why isn't the 'HelperChild' printed in the last line? What changes do I have to do to achieve this? (I'm not sure if I have used virtual in the correct way).
EDIT: In the actual case im trying to figure out, Base::print is a really large method that I don't want to override in the Child class. I just want to change the behaviour of the helper class.
Copy constructor will NOT copy derived object, it will get sliced and create a base object.
To elaborate, you may consider copy constructor as "copy by value", every value of derived object would be copied to create a base object. Since your Helper classes have no class members, it copied nothing.
Also function is not copyable, C++ handles virtual functions by vtable. A base class would have a vtable of base class, that's why hb.something() called the base version.
Last line is printing Helper base because your Base has a HelperBase but not a derived HelperChild.
class Base {
public:
Base(HelperBase &helperBase) : hb(helperBase) {} // hp(helperBase) means you still have a helper base.
virtual void print() {
std::cout << "-- Base" << std::endl;
hb.something();
}
HelperBase hb;
};
Then in main, child.print() will call the hb.something() which belongs to HelperBase.
To achieve polymorphism, you need a pointer to take the instance of HelperChild. It's called Dependency Injection and I assumed you were trying to achieve it.
class Base {
public:
Base(HelperBase &helperBase) {
hb = &helperBase;
}
virtual void print() {
std::cout << "-- Base" << std::endl;
hb->something();
}
HelperBase* hb;
};
The HelperBase hb in class Base is always of type HelperBase - even if you call print from an instance of type Child.
There are various ways to achieve what you want. One option is to use PIMPL to store a pointer to a Helper class. A different option is to use CRTP.
I have those objects:
class A{
public:
void print();
}
class B : public A{
public:
void print();
}
class C : public A{
public:
void print();
}
The function print:
void A::print(){
cout << "A" << endl;
}
void B::print(){
cout << "B" << endl;
}
void C::print(){
cout << "C" << endl;
}
Now I have a vector of A objects which can contain A B or C
for(unsigned int i = 0; i<m_vA.size(); i++)
{
cout << m_vA[i]->print() << endl;
}
But each time the function returns A even if this is a B or C object
Thanks for the help
You do not override the function. To do so, use "virtual" keyword while declaring this function in A class.
You forgot to make the member function virtual.
The short answer is: use virtual as the other answers indicate, so that you override the function, instead of hiding it.
Here's an excerpt from Herb Sutter's Exceptional C++ - Item 21: Overriding Virtual Functions which explains in more detail what is going on with your code:
It's important to differentiate between three common terms:
To overload a function f() means to provide another function with the same name f() in the same scope but with different
parameter types. When f() is actually called, the compiler will try
to pick the best match based on the actual parameters that are
supplied.
To override a virtual function f() means to provide another function with the same name f() and the same parameter types in a
derived class.
To hide a function f() in an enclosing scope (base class, outer class, or namespace) means to provide another function with the same
name f() in an inner scope (derived class, nested class, or
namespace), which will hide the same function name in an enclosing
scope.
Because your various print functions are in nested scopes, and because you have not provided the virtual keyword, each function is hiding the functions of the same name in the base class(es):
class A{
public:
void print();
}
class B : public A{
public:
void print(); // Hides A::print()
}
class C : public A{
public:
void print(); // Hides A::print() and B::print()
}
So, when the compiler performs name resolution, it will look within the current scope (which is the class definition for the type from which you have called the function) and it will stop there because it will find a non-virtual function with the name print.
Polymorphism requires the use of the virtual keyword to declare that the method should be stored in a virtual table (vtable), and its implementation looked-up at runtime.
Note also that your class definitions need semicolons after the closing brackets.
class A
{
public:
virtual void print()
{
cout << "A" << endl;
}
};
class B : public A
{
public:
virtual void print() override
{
cout << "B" << endl;
}
};
class C : public A
{
public:
virtual void print() override
{
cout << "C" << endl;
}
};
On a side note, the virtual keyword in the derived classes is not necessary (it's implicitly added in derived classes if the base class function is declared virtual), but good to use for readability and to avoid potential issues with the odd compiler that requires it. The override identifier is also not necessary, but forces the compiler to check that you are in fact overriding a virtual function that exists in the superclass. (I think override is only available in C++11).
I wanted to have confirmation about the following things:
Virtual Mechanism:
I f I have a base class A and it has a Virtual method, then in the derived class generally, we do not include the virtual statement in the function declaration. But what does a virtual mean when included at the dervied class definition.
class A
{
public:
virtual void something();
}
class B:public A
{
public:
virtual void something();
}
Does, that mean that we want to override the method somethign in the classes that derive from the class B?
Also, another question is,
I have a class A, which is derived by three different classes.Now, there is a virtual method anything(), in the base class A.
Now, if I were to add a new default argument to that method in the base class, A::anything(), I need to add it in all the 3 classes too right.
My pick for the answers:
If a method which is virtual in the base class is redefined in the derived class as virtual then we might mean that it shall be overridden in the corresponding derived classes which uses this class as base class.
Yes.If not overriding does not have any meaning.
Pls let me know if what I feel(above 2) are correct.
Thanks,
Pavan Moanr.
The virtual keyword can be omitted on the override in the derived classes. If the overridden function in the base class is virtual, the override is assumed to be virtual as well.
This is well covered in this question: In C++, is a function automatically virtual if it overrides a virtual function?
Your second question is about default values and virtual functions. Basically, each override can have a different default value. However, usually this will not do what you expect it to do, so my advice is: do not mix default values and virtual functions.
Whether the base class function is defaulted or not, is totally independent from whether the derived class function is defaulted.
The basic idea is that the static type will be used to find the default value, if any is defined. For virtual functions, the dynamic type will be used to find the called function.
So when dynamic and static type don't match, unexpected results will follow.
e.g.
#include <iostream>
class A
{
public:
virtual void foo(int n = 1) { std::cout << "A::foo(" << n << ")" << std::endl; }
};
class B : public A
{
public:
virtual void foo(int n = 2) { std::cout << "B::foo(" << n << ")" << std::endl; }
};
int main()
{
A a;
B b;
a.foo(); // prints "A::foo(1)";
b.foo(); // prints "B::foo(2)";
A& ref = b;
ref.foo(); // prints "B::foo(1)";
}
If all your overrides share the same default, another solution is to define an additional function in the base class that does nothing but call the virtual function with the default argument. That is:
class A
{
public:
void defaultFoo() { foo(1); }
virtual void foo(int n) { .... }
};
If your overrides have different defaults, you have two options:
make the defaultFoo() virtual as well, which might result in unexpected results if a derived class overload one but not the other.
do not use defaults, but explicitly state the used value in each call.
I prefer the latter.
It doesn't matter whether you write virtual in derived class or not, it will always be virtual because of the base class, however it is still better to include virtual to explicitly state that it is virtual and then if you accidentally remove that keyword from base class it will give you compiler error (you cannot redefine non-virtual function with a virtual one). EDIT >> sorry, I was wrong. You can redefine non-virtual function with a virtual one however once it's virtual all derived classes' functions with same signature will be virtual too even if you don't write virtual keyword. <<
If you don't redefine virtual function then the definition from base class will be used (as if it were copied verbatim).
If you wish to specify that a virtual function should be redefined in dervied class you should not provide any implementation i.e. virtual void something() = 0;
In this case your class will be an abstract base class (ABC) and no objects can be instantiated from it. If derived class doesn't provide it's own implementetian it will also be an ABC.
I'm not sure what do you mean about default arguments but function signatures should match so all parameters and return values should be the same (it's best to not mix overloading/default arguments with inheritance because you can get very surprising results for example:
class A
{
public:
void f(int x);
};
class B:public A
{
public:
void f(float x);
};
int main() {
B b;
b.f(42); //this will call B::f(float) even though 42 is int
}
Here is a little experiment to test out what you want to know:
class A {
public:
virtual void func( const char* arg = "A's default arg" ) {
cout << "A::func( " << arg << " )" << endl;
}
};
class B : public A {
public:
void func( const char* arg = "B's default arg" ) {
cout << "B::func( " << arg << " )" << endl;
}
};
class C : public B {
public:
void func( const char* arg ) {
cout << "C::func( " << arg << " )" << endl;
}
};
int main(int argc, char* argv[])
{
B* b = new B();
A* b2 = b;
A* c = new C();
b->func();
b2->func();
c->func();
return 0;
}
result:
B::func( B's default arg )
B::func( A's default arg )
C::func( A's default arg )
conclusion:
1- virtual keyword before A's func declaration makes that function virtual in B and C too.
2- The default argument used is the one declared in the class of pointer/reference you are using to access the object.
As someone pointed out, a function in a derived class with the same name and type signature as a virtual function in the base class is automatically always a virtual function.
But your second question about default arguments is interesting. Here is a tool for thinking through the problem...
class A {
public:
virtual void do_stuff_with_defaults(int a = 5, char foo = 'c');
};
is nearly equivalent to this:
class A {
public:
virtual void do_stuff_with_defaults(int a, char foo);
void do_stuff_with_defaults() { // Note lack of virtual keyword
do_stuff_with_defaults(5, 'c'); // Calls virtual function
}
void do_stuff_with_defaults(int a) { // Note lack of virtual keyword
do_stuff_with_defaults(a, 'c'); // Calls virtual functions
}
};
Therefore you are basically having virtual and non-virtual functions with the same name but different type signatures declared in the class if you give your virtual function default arguments.
On way it isn't equivalent has to do with being able to import names from the base class with the using directive. If you declare the default arguments as separate functions, it's possible to import those functions using the using directive. If you simply declare default arguments, it isn't.
I have, for example, such class:
class Base
{
public: void SomeFunc() { std::cout << "la-la-la\n"; }
};
I derive new one from it:
class Child : public Base
{
void SomeFunc()
{
// Call somehow code from base class
std::cout << "Hello from child\n";
}
};
And I want to see:
la-la-la
Hello from child
Can I call method from derived class?
Sure:
void SomeFunc()
{
Base::SomeFunc();
std::cout << "Hello from child\n";
}
Btw since Base::SomeFunc() is not declared virtual, Derived::SomeFunc() hides it in the base class instead of overriding it, which is surely going to cause some nasty surprises in the long run. So you may want to change your declaration to
public: virtual void SomeFunc() { ... }
This automatically makes Derived::SomeFunc() virtual as well, although you may prefer explicitly declaring it so, for the purpose of clarity.
class Child : public Base
{
void SomeFunc()
{
// Call somehow code from base class
Base::SomeFunc();
std::cout << "Hello from child\n";
}
};
btw you might want to make Derived::SomeFunc public too.
You do this by calling the function again prefixed with the parents class name. You have to prefix the class name because there maybe multiple parents that provide a function named SomeFunc. If there were a free function named SomeFunc and you wished to call that instead ::SomeFunc would get the job done.
class Child : public Base
{
void SomeFunc()
{
Base::SomeFunc();
std::cout << "Hello from child\n";
}
};
Yes, you can. Notice that you given methods the same name without qualifying them as virtual and compiler should notice it too.
class Child : public Base
{
void SomeFunc()
{
Base::SomeFunc();
std::cout << "Hello from child\n";
}
};