I understand the basic concept of virtual function and vtable,
but in the following example, I don't understand why c.A(); prints out
parent A
child
but without the virtual keyword for Parent::func(), it prints out
parent A
parent
Would you let me know the reason in detail? It would be great to explain with v table, memory (heap, stack), etc..
Thanks.
#include <iostream>
template <class TYPE> class Parent
{
public:
Parent() {};
~Parent() {};
virtual void func() { std::cout << "parent" << std::endl; };
void A() {
std::cout << "parent A" << std::endl;
func();
}
};
template <class TYPE> class Child : public Parent <TYPE>
{
public:
Child() {};
~Child() {};
void func() { std::cout << "child" << std::endl; };
};
void main()
{
Child<int> c;
c.A();
}
The virtual key word specifies that the function can be redefined in a derived class, while preserving its calling properties though references. This is basically the trigger for polymorphic behavior. If the function is declared virtual and it is redefined in a derived class then the vtable is utilized to select the appropriate version of the function unless a specific namespace is specified. For example Parent::func(). Despite having the same name, without the key word virtual the two functions you named func() are completely different. There is no reference available to the base class that can access the derived class's version of the function. It uses the only version func() it knows about, which is the one defined in the base class.
#Pemdas gave a nice explanation. Here is my try.
c.A() tells compiler "I am gonna call the non virtual function A defined in my parent class". This translates to Parent::A(&c)
The A method in class Parent translates to "get the vtable of object &c, grab the function pointer in first row, and call it". Since c reimplements the function func, the function pointer would be c's implementation of function func. That would be what you see.
Related
I am trying to understand why the following code does not compile, apparently the solution relies in specifically declaring the dependency on method_A in the derived class.
Please refer to the following code:
class Base
{
public:
void method_A(int param, int param2)
{
std::cout << "Base call A" << std::endl;
}
};
//does not compile
class Derived : public Base
{
public:
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
//compiles
class Derived2 : public Base
{
public:
using Base::method_A; //compile
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
int main ()
{
Derived myDerived;
myDerived.method_A(1);
myDerived.method_A(1,2);
Derived2 myDerived2;
myDerived2.method_A(1);
myDerived2.method_A(1,2);
return 0;
}
"test.cpp", (S) The wrong number of arguments have been specified for "Derived::method_A(int)".
What is the technical reason that prevents the derived class to know its base class is implementing the method it's trying to overload?
I am looking in understanding better how the compiler/linker behaves in this case.
Its called Name Hiding. When you define a non virtual method with the same name as Base method it hides the Base class method in Derived class so you are getting the error for
myDerived.method_A(1,2);
To avoid hiding of Base class methods in Derived class use using keyword as you did in Derived2 class.
Also if you want to make it work you can do it explictly
myDerived.Base::method_A(1,2);
Check out this for better explanation why name hiding came into picture.
Well, for one you're calling
myDerived.method_A(1,2);
with 2 arguments, whereas both in base and derived the method is declared to take only one argument.
Secodnly, you're not overriding anything, because method_A is not virtual. You're overloading.
If your intention is to override void Base::method_A(int param, int param2) then you should mark it virtual in the base class:
virtual void method_A(int param, int param2)
Any function overriding this must have the same parameters and almost the same return type ('almost' loosely meaning that the differing return types must be polymorphically related, but in most cases it should have the identical return type).
All you're currently doing is overloading the function in the base class. The using keyword is bringing the base class function into the child class' namespace, as the language behaviour is not to do this by default.
So I recently accidentally called some virtual functions from the constructor of a base class, i.e. Calling virtual functions inside constructors.
I realise that I should not do this because overrides of the virtual function will not be called, but how can I achieve some similar functionality? My use-case is that I want a particular function to be run whenever an object is constructed, and I don't want people who write derived classes to have to worry about what this is doing (because of course they could call this thing in their derived class constructor). But, the function that needs to be called in-turn happens to call a virtual function, which I want to allow the derived class the ability to override if they want.
But because a virtual function gets called, I can't just stick this function in the constructor of the base class and have it get run automatically that way. So I seem to be stuck.
Is there some other way to achieve what I want?
edit: I happen to be using the CRTP to access other methods in the derived class from the base class, can I perhaps use that instead of virtual functions in the constructor? Or is much the same issue present then? I guess perhaps it can work if the function being called is static?
edit2: Also just found this similar question: Call virtual method immediately after construction
If really needed, and you have access to the factory.
You may do something like:
template <typename Derived, typename ... Args>
std::unique_ptr<Derived> Make(Args&&... args)
{
auto derived = std::make_unique<Derived>(std::forward<Args>(args));
derived->init(); // virtual call
return derived;
}
There is no simple way to do this. One option would be to use so-called virtual constructor idiom, hide all constructors of the base class, and instead expose static 'create' - which will dynamically create an object, call your virtual override on it and return (smart)pointer.
This is ugly, and what is more important, constrains you to dynamically created objects, which is not the best thing.
However, the best solution is to use as little of OOP as possible. C++ strength (contrary to popular belief) is in it's non-OOP specific traits. Think about it - the only family of polymorphic classess inside standard library are streams, which everybody hate (because they are polymorphic!)
I want a particular function to be run whenever an object is constructed, [... it] in-turn happens to call a virtual function, which I want to allow the derived class the ability to override if they want.
This can be easily done if you're willing to live with two restrictions:
the constructors in the entire class hierarchy must be non-public, and thus
a factory template class must be used to construct the derived class.
Here, the "particular function" is Base::check, and the virtual function is Base::method.
First, we establish the base class. It has to fulfill only two requirements:
It must befriend MakeBase, its checker class. I assume that you want the Base::check method to be private and only usable by the factory. If it's public, you won't need MakeBase, of course.
The constructor must be protected.
https://github.com/KubaO/stackoverflown/tree/master/questions/imbue-constructor-35658459
#include <iostream>
#include <utility>
#include <type_traits>
using namespace std;
class Base {
friend class MakeBase;
void check() {
cout << "check()" << endl;
method();
}
protected:
Base() { cout << "Base()" << endl; }
public:
virtual ~Base() {}
virtual void method() {}
};
The templated CRTP factory derives from a base class that's friends with Base and thus has access to the private checker method; it also has access to the protected constructors in order to construct any of the derived classes.
class MakeBase {
protected:
static void check(Base * b) { b->check(); }
};
The factory class can issue a readable compile-time error message if you inadvertently use it on a class not derived from Base:
template <class C> class Make : public C, MakeBase {
public:
template <typename... Args> Make(Args&&... args) : C(std::forward<Args>(args)...) {
static_assert(std::is_base_of<Base, C>::value,
"Make requires a class derived from Base");
check(this);
}
};
The derived classes must have a protected constructor:
class Derived : public Base {
int a;
protected:
Derived(int a) : a(a) { cout << "Derived() " << endl; }
void method() override { cout << ">" << a << "<" << endl; }
};
int main()
{
Make<Derived> d(3);
}
Output:
Base()
Derived()
check()
>3<
If you take a look at how others solved this problem, you will notice that they simply transferred the responsibility of calling the initialization function to client. Take MFC’s CWnd, for instance: you have the constructor and you have Create, a virtual function that you must call to have a proper CWnd instantiation: “these are my rules: construct, then initialize; obey, or you’ll get in trouble”.
Yes, it is error prone, but it is better than the alternative: “It has been suggested that this rule is an implementation artifact. It is not so. In fact, it would be noticeably easier to implement the unsafe rule of calling virtual functions from constructors exactly as from other functions. However, that would imply that no virtual function could be written to rely on invariants established by base classes. That would be a terrible mess.” - Stroustrup. What he meant, I reckon, is that it would be easier to set the virtual table pointer to point to the VT of derived class instead of keep changing it to the VT of current class as your constructor call goes from base down.
I realise that I should not do this because overrides of the virtual function will not be called,...
Assuming that the call to a virtual function would work the way you want, you shouldn't do this because of the invariants.
class B // written by you
{
public:
B() { f(); }
virtual void f() {}
};
class D : public B // written by client
{
int* p;
public:
D() : p( new int ) {}
void f() override { *p = 10; } // relies on correct initialization of p
};
int main()
{
D d;
return 0;
}
What if it would be possible to call D::f from B via VT of D? You will use an uninitialized pointer, which will most likely result in a crash.
...but how can I achieve some similar functionality?
If you are willing to break the rules, I guess that it might be possible to get the address of desired virtual table and call the virtual function from constructor.
Seems you want this, or need more details.
class B
{
void templateMethod()
{
foo();
bar();
}
virtual void foo() = 0;
virtual void bar() = 0;
};
class D : public B
{
public:
D()
{
templateMethod();
}
virtual void foo()
{
cout << "D::foo()";
}
virtual void bar()
{
cout << "D::bar()";
}
};
I am trying to understand why the following code does not compile, apparently the solution relies in specifically declaring the dependency on method_A in the derived class.
Please refer to the following code:
class Base
{
public:
void method_A(int param, int param2)
{
std::cout << "Base call A" << std::endl;
}
};
//does not compile
class Derived : public Base
{
public:
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
//compiles
class Derived2 : public Base
{
public:
using Base::method_A; //compile
void method_A(int param)
{
std::cout << "Derived call A" << std::endl;
}
};
int main ()
{
Derived myDerived;
myDerived.method_A(1);
myDerived.method_A(1,2);
Derived2 myDerived2;
myDerived2.method_A(1);
myDerived2.method_A(1,2);
return 0;
}
"test.cpp", (S) The wrong number of arguments have been specified for "Derived::method_A(int)".
What is the technical reason that prevents the derived class to know its base class is implementing the method it's trying to overload?
I am looking in understanding better how the compiler/linker behaves in this case.
Its called Name Hiding. When you define a non virtual method with the same name as Base method it hides the Base class method in Derived class so you are getting the error for
myDerived.method_A(1,2);
To avoid hiding of Base class methods in Derived class use using keyword as you did in Derived2 class.
Also if you want to make it work you can do it explictly
myDerived.Base::method_A(1,2);
Check out this for better explanation why name hiding came into picture.
Well, for one you're calling
myDerived.method_A(1,2);
with 2 arguments, whereas both in base and derived the method is declared to take only one argument.
Secodnly, you're not overriding anything, because method_A is not virtual. You're overloading.
If your intention is to override void Base::method_A(int param, int param2) then you should mark it virtual in the base class:
virtual void method_A(int param, int param2)
Any function overriding this must have the same parameters and almost the same return type ('almost' loosely meaning that the differing return types must be polymorphically related, but in most cases it should have the identical return type).
All you're currently doing is overloading the function in the base class. The using keyword is bringing the base class function into the child class' namespace, as the language behaviour is not to do this by default.
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";
}
};