Does a VTBL contains pointers to non-virtual functions? [duplicate] - c++

This question already has answers here:
In C++, is a function automatically virtual if it overrides a virtual function?
(4 answers)
Closed 5 years ago.
I'm having hard time to understand why the code below print C::f2 instead of B::f2.
From Charles Bailey answer:
When a non-virtual function is called the implementation must use the
static type of the object on which the function is being called to
determine the correct function to call. A function stored in a vtable
accessed by a vptr will be dependent on the dynamic type of the
object, not any static type of a reference or pointer through which it
is being accessed.
I'm a bit lost, Inside A::f1 there is a call to f2. How does the compiler know which method to call?
My assemption:
The compiler somehow remmber that we are inside object of type C.
The compiler check if C contain a non virtual method name f2.
a. if yes, run it.
b. use the object's pointer to access his vtbl and run the right f2.
Am I right?
struct A
{
void f1()
{
f2();
}
virtual void f2()
{
cout<<"A::f2"<<endl;
}
};
struct B:public A
{
virtual void f2()
{
cout<<"B::f2"<<endl;
}
};
struct C:public B
{
void f2()
{
cout<<"C::f2"<<endl;
}
};
int main()
{
C c1;
c1.f1();
return 0;
}

Every member function has an implicit this parameter. The static type of this inside f1 is always A * const. This is true for any member function. The static type of the implicit object parameter is the enclosing class where the function is defined.
The call inside f1 is resolved as this->f2(). Since this is a call via pointer, the function f2 is dispatched dynamically. This is despite the fact the f1 is not virtual, and will always be called by static dispatch.
By whatever mechanism the compiler uses (a VTable is an implementation detail, not mandated by the C++ standard itself), we get a call to C::f2.
So your assumptions need some revision, I'd say.
To answer your question as you specified in the comments. C::f2 is virtual. You may have omitted the virtual specifier when overriding it, but there is no "unvirtualising" it.

Related

How does compiler decides when to use a vPtr to invoke a function

How to identify whether vptr will be used to invoke a virtual function?
Consider the below hierarchy:
class A
{
int n;
public:
virtual void funcA()
{std::cout <<"A::funcA()" << std::endl;}
};
class B: public A
{
public:
virtual void funcB()
{std::cout <<"B::funcB()" << std::endl;}
};
A* obj = new B();
obj->funcB(); //1. this does not even compile
typedef void (*fB)();
fB* func;
int* vptr = (int*)obj; //2. Accessing the vptr
func = (fB*)(*vptr);
func[1](); //3. Calling funcB using vptr.
Statement 1. i.e. obj->funcB(); does not even compile although Vtable has an entry for funcB where as on accessing vPtr indirectly funcB() can be invoked successfully.
How does compiler decide when to use the vTable to invoke a function?
In the statement A* obj = new B(); since I am using a base class pointer so I believe vtable should be used to invoke the function.
Below is the memory layout when vptr is accessed indirectly.
So there are two answers to your question:
The short one is:
obj->FuncB() is only a legal call, if the static type of obj (in this case A) has a function FuncB with the appropriate signature (either directly or due to a base class). Only if that is the case, the compiler decides whether it translates it to a direct or dynamic function call (e.g. using a vtable), based on whether FuncB is declared virtual or not in the declaration of A (or its base type).
The longer one is this:
When the compiler sees obj->funcB() it has no way of knowing (optimizations aside), what the runtime type of obj is and especially it doesn't know, whether a derived class that implements funcB() exists, at all. obj might e.g. be created in another translation unit or it might be a function parameter.
And no, that information is usually not stored in the virtual function table:
The vtable is just an array of addresses and without the prior knowledge that a specific addess corresponds to a function called funcB, the compiler can't use it to implement the call obj->funcB()- or to be more precise: it is not allowed to do so by the standard. That prior knowledge can only be provided by a virtual function declaration in the static type of obj (or its base classes).
The reason, why you have that information available in the debugger (whose behavior lys outside of the standard anyway) is, because it has access to the debugging symbols, which are usually not part of the distributed release binary. Storing that information in the vtable by default, would be a waste of memory and performance, as the program isn't allowed to make use of it in standard c++ in the way you describe anyway. For extensions like C++/CLI that might be a different story.
Adding to Barry's comment, adding the line virtual void funcB() = 0; to class A seems to fix the problem.

c++ virtual function call without pointer or reference

As far as I know, virtual function call usually requires pointer or reference. So I am very surprised by the following codes.
#include <iostream>
using namespace std;
class B{
public:
void runB(){ call(); }
virtual void call(){ cout<<"B\n"; };
};
class D: public B{
public:
void runD(){ runB(); }
void call(){ cout<<"D\n"; }
};
int main(){
D d;
d.runD();
}
The output is
D
Could someone please comment why this virtual function call works? Thanks。
Within a member function, any references to other member functions or variables are implicitly resolved via the this pointer. So in the definition of runB(), the call() really means this->call(). The virtual function call is performed using the current object's virtual table.
Firstly, virtual function call does not require a pointer or a reference. As far as the language is concerned, any call to virtual function is a virtual call, unless you explicitly suppress the virtual dispatch mechanism by using a qualified function name. For example, these
d.D::call(); // calls `D::call()` directly
d.B::call(); // calls `B::call()` directly
are calls which were explicitly forced to be non-virtual. However, this
d.call(); // calls `D::call()` virtually
is a virtual call. In this case it is immediately obvious to the compiler that the target function is D::call(), so the compiler normally optimizes this virtual call into a regular direct call. Yet, conceptually, d.call() is still a virtual call.
Secondly, the call to call() made inside B::runB() is made through a pointer. The pointer is present there implicitly. Writing call() inside B::runB() is just a shorthand for (*this).call(). this is a pointer. So that call is made through a pointer.
Thirdly, the key property of virtual call is that the target function is chosen in accordance with the dynamic type of the object used in the call. In your case, even when you are inside B::runB() the dynamic type of the object *this is D. Which is why it calls D::call(), as it should.
Fourthly, what you really need a pointer or a reference for is to observe the actual polymorphism. Polymorphism proper occurs when static type of the object expression used in the call is different from its dynamic type. For that you do indeed need a pointer or a reference. And that is exactly what you observe in that (*this).call() call inside B::runB(). Even though the static type of *this is B, its dynamic type is D and the call is dispatched to D::call().
The difference between virtual to not virtual is:
not virtual - always goes by the caller object/reference/pointer type.
virtual - reference/pointer - goes by the created object type.
virtual - object - goes by the caller.
for example:
class A{
public:
virtual void f(){
cout <<"A\n";
}
};
class B: public A{
public:
virtual void f(){
cout <<"B\n";
}
};
B b;
A a,*pa=&b;
a.f(); //A: caller type = created type - same for not virtual
b.f(); //B: caller type = created type - same for not virtual
((A)b).f(); //A: object goes by the caller type - same for not virtual
pa->f(); // B: pointer goes by the created type - it would be A if it was not virtual!!

what 0 means in pure virtual function [duplicate]

This question already has answers here:
Why is a pure virtual function initialized by 0?
(11 answers)
Closed 10 years ago.
Program below doesn't compile for obvious reasons:
#include <iostream>
using namespace std;
class A {
public:
A() { pVirt(); }
virtual void pVirt() const = 0 { count<<"A::pVirt()"; }
};
int main() {
A aObj;
aObj.pVirt();
reutrn 0;
}
Questions:
1. 0 in signature "virtual void pVirt() const = 0" means what?, Is this indicates NULL memory offset in vtable or just a syntax constraint?
If 0 is NULL memory offset (if in case it is so) then why VC++ doesn't allow to specify another memory address, and is this the reason why we can't call pure virtual function from outside constructor (MAY BE because vtable is created after an object is fully constructed.)?
0 in signature "virtual void pVirt() const = 0" means what?,
The part =0 is called pure-specifier. It makes the virtual function pure, and the class abstract.
A pure virtual function need not to have definition. You may optionally provide a definition outside the class, and a non-abstract derived class still has to override the function.
class A
{
public:
virtual ~A() {};
virtual void f() =0;
};
void A::f() { std::cout << "A::f" << std::endl; } //optional
The definition of f doesn't make the class non-abstract, so you cannot create instance of A:
A a; //error - A is abstract
Moreover, the derive class has to override A::f in order to be non-abstract:
class B : public A {};
B b; //error : B is still an abstract class as it didn't override A::f
And
class C : public A { void f() {} };
C c; //okay : C override A::f
And derived class implementation may choose to call the base class implementation:
class D : public A { void f() { A::f(); } }; //defaults to A::f
D d; //okay : D override A::f, but calls A::f internally
Hope that helps.
It’s just syntax to denote that the function is pure virtual. It has no actual meaning whatsoever. The C++ designers could just as well chosen to use pure or abstract in place of = 0. I suspect the only reason for not doing so was that they didn’t want to introduce a new reserved word into the language (since that breaks any existing code which already uses the newly reserved word as an identifier).
(It’s not necessary to make such a word reserved since it would be a context sensitive keyword, but the concept of context sensitive keywords has only recently entered mainstream usage, and this syntax is much older.)
The = 0 in the function declaration is just syntax: the two
token sequence means that the function is pure, that's all. And
you cannot replace either of the tokens with anything else: =
0L isn't legal, for example.
And the reason you're getting the error is simply because the
syntax isn't allowed. For historical reasons, if nothing else.
If you want to provide a definition for a pure virtual function,
you must do it outside of the class.
And if you provide a definition for a pure virtual function,
you can call it from the constructor; you just have to
disactivate the virtual call mechanism; e.g. A::pVirt(). If
the actual function call involves dynamic resolution, and the
resolution results in a pure virtual function, it is undefined
behavior, regardless of whether the function is defined or not.
The motivation here is to allow you not to define it; normally,
a virtual function must be defined, whether you call it or not,
because the compiler must put its address in the vtable, and
if it isn't defined, there is no address. Making the function
pure virtual tells the compiler that it shouldn't put its
address in the vtable. So you don't have to define it. But
you may get surprises if you try to call the function through
the vtable.
The = 0 after a virtual function means that "this is pure virtual function, it must be implemented in the derived function". As in your example, it's still possible to implement the function. It has no other meaning as such - and you can't use other numbers, addresses or anything else. You can have several functions with =0, and it will still be the same meaning.

Why is a virtual table required only in case of virtual functions?

From http://www.learncpp.com/cpp-tutorial/125-the-virtual-table/, code such as
class Base
{
public:
virtual void function1() {};
virtual void function2() {};
};
class D1: public Base
{
public:
virtual void function1() {};
};
class D2: public Base
{
public:
virtual void function2() {};
};
generates a virtual table similar to http://www.learncpp.com/images/CppTutorial/Section12/VTable.gif:
The virtual table as above makes sense. After all the objects need a way to call functions, and need to use function pointers to find them.
What I do not understand is why this is only required in case of using virtual functions? I am definitely missing something since a virtual table does not directly depend on virtual functions.
As an example, if the code being used were
class Base
{
public:
void function1() {};
void function2() {};
};
...
Base b;
b.function1();
and there is no virtual table (meaning there is no pointer to where the function resides), how would the b.function1() call resolve?
Or is it that we have a table in this case as well, just that it is not called a virtual table? In that case the question would arise as to why we need a new kind of table for virtual functions?
[If] there is no virtual table (meaning there is no pointer to where the function resides), how would the b.function1() call resolve?
There is a "pointer", inside the compiler as it's parsing and analysing your code. The compiler's the thing that decides where the function will be generated, so it knows how calls to said function should resolve. In concert with the linker, this all happens tidily within the build process.
The only reason that this doesn't work for virtual functions is that which function you call depends on a type known only at runtime; in fact the same function pointers are present verbatim in the virtual table, written there by the compiler. It's just that in this case, there are multiple to choose from, and they cannot be chosen from until long (read: potentially months or even years!) after the compiler ceases to be involved at all.
There's already a good answer, but I'll attempt a slightly simpler (albeit longer) one:
Think of a non-virtual method of the form
class A
{
public:
int fn(int arg1);
};
as equivalent to a free function of the form:
int fn(A* me, int arg1); // overload A
where me corresponds to the this pointer inside the method version.
If you now have a subclass:
class B : public A
{
public:
int fn(int arg1);
};
this is equivalent to a free function like this:
int fn(B* me, int arg1); // overload B
Note that the first argument has a different type to the free function we declared earlier - the function is overloaded on the type of the first argument.
If you now have some code calling fn() it will choose the overload based on the static type (compile time type) of the first argument:
A* p;
B* q;
// ...
// assign valid pointer values to p and q
// ...
int a = fn(p, 0); // will call overload A
int b = fn(q, 0); // will call overload B
The compiler can and will determine the function to call at compile time in each case and can emit assembly code with a fixed function address or address offset. The concept of a runtime virtual table is nonsensical here.
Now, when I said to think of the method version as equivalent to the free function version, you'll find that at the assembly language level, they are equivalent. The only difference will be the so-called mangled name that encodes the type in the compiled function name and distinguishes overloaded functions. The fact that you call methods via p->fn(0), that is, with the first argument before the method name is pure syntactic sugar - you're not actually dereferencing the pointer p in the example, even though it looks like it. You're just passing p as the implicit this argument. So, to continue the above example,
p->fn(0); // will always call A::fn()
q->fn(0); // will always call B::fn()
because fn being a non-virtual method means the compiler dispatches on the this pointer's static type, which it can do at compile time.
Although virtual functions use the same calling syntax as non-virtual member functions, you are in fact dereferencing the object pointer; specifically, you're dereferencing the pointer to the object's class's virtual table.

function pointer and virtual function

I guess my question should be silly but it is true that I have never seen a function pointer that is declared as virtual. Is there a reason for this?
Edit:
I should have said: Is it possible that the function it points to is specified as virtual?
Well, yes (and no).
Ordinary function pointers cannot point to non-static member functions. They can only point to standalone functions, which is why for ordinary function pointers the matter of function virtuality does not even come into the picture.
In order to point to member functions in C++ you need a pointer of special kind: one that has pointer-to-member-function type. A pointer of this type can point to non-virtual member functions as well and to virtual member functions. There are no special steps to take if you want to point to virtual member function. For example
struct B {
virtual void foo() {}
void bar() {}
};
...
B b;
void (B::*pfunc)(); // declare a pointer to a member function
pfunc = &B::foo; // make it point to `B::foo`
(b.*pfunc)(); // calls `B::foo` for object `b`
pfunc = &B::bar; // make it point to `B::bar`
(b.*pfunc)(); // calls `B::bar` for object `b`
However, when you make such pointer to point to a virtual member function, you have to keep in mind that it is does not really get tied to a specific version of that function in the class hierarchy. The decision about the specific function to call is made at the point of the call. For example
// given the above `B`
struct D : B {
virtual void foo() {}
};
...
void (B::*pfoo)(); // declare a pointer to a member function
pfoo = &B::foo; // and make it point to `B::foo`
In the above example we made out pointer pfoo to point to B::foo. Or did we? In reality the pointer is not hard-linked to B::foo specifically. These two calls
B b;
D d;
(b.*pfoo)();
(d.*pfoo)();
will call two different functions. The first one will call B::foo for object b, while the second one will call D::foo for object d, even though we used the same pointer value in both cases. This makes sense actually in many applications.
Yet, in some low-level situation it would be useful to have a pointer that is hard-tied to a specific version of virtual function. I.e. it would be nice to have a pointer that would call B::foo for B subobject of object d when we do
(d.*pfoo)();
To achieve that we need to be able to specify whether we want to bind it early (at the point of initialization) or late (at the point of the call). Unfortunately, C++ language provides no such functionality.
A Function pointer is just a pointer to the function. It just stores address of an function just like any pointer to a type stores address of an type.
keyword virtual is used to implement polymorphic behavior(between functions of base class and derived class)through dynamic dispatch.
Given the above two are distinctly different and the idea of a function pointer to be virtual makes no sense at all.
whether the function it points to is specified as virtual ?
As I mentioned before an function pointer just stores address of an function. It is just an type. For eg:
int *i = NULL;
void doSomething();
typedef void(*ptr)() = NULL;
ptr = &doSomething();
In above example:
i is a type of int *. Similarly,
ptr is a type which can store address of an function which takes no parameter and returns no parameter.
So Yes, fundamentally, you can make the function to which a function pointer points as virtual, just like you would make any function virtual by declaring the particular function as virtual in the class.
The function pointer being a type can point to any function with that prototype, while declaring a function as virtual means having dynamic dispatch enabled on a particular function, as you see both are not the same.
Virtuality is a property of member functions. If you have a pointer to a virtual member function then a virtual call will be made automatically. Regular functions can't be virtual, so a virtual function pointer makes no sense. In either case there's no point making a function pointer virtual as its the function being pointed to that counts.