C++ : How does Virtual Function resolve "this" pointer scope issue? - c++

(C++,MinGW 4.4.0,Windows OS)
All that is commented in the code, except labels <1> and <2>, is my guess. Please correct me in case you think I'm wrong somewhere:
class A {
public:
virtual void disp(); //not necessary to define as placeholder in vtable entry will be
//overwritten when derived class's vtable entry is prepared after
//invoking Base ctor (unless we do new A instead of new B in main() below)
};
class B :public A {
public:
B() : x(100) {}
void disp() {std::printf("%d",x);}
int x;
};
int main() {
A* aptr=new B; //memory model and vtable of B (say vtbl_B) is assigned to aptr
aptr->disp(); //<1> no error
std::printf("%d",aptr->x); //<2> error -> A knows nothing about x
}
<2> is an error and is obvious. Why <1> is not an error? What I think is happening for this invocation is: aptr->disp(); --> (*aptr->*(vtbl_B + offset to disp))(aptr) aptr in the parameter being the implicit this pointer to the member function. Inside disp() we would have std::printf("%d",x); --> std::printf("%d",aptr->x); SAME AS std::printf("%d",this->x); So why does <1> give no error while <2> does?
(I know vtables are implementation specific and stuff but I still think it's worth asking the question)

this is not the same as aptr inside B::disp. The B::disp implementation takes this as B*, just like any other method of B. When you invoke virtual method via A* pointer, it is converted to B* first (which may even change its value so it is not necessarily equal to aptr during the call).
I.e. what really happens is something like
typedef void (A::*disp_fn_t)();
disp_fn_t methodPtr = aptr->vtable[index_of_disp]; // methodPtr == &B::disp
B* b = static_cast<B*>(aptr);
(b->*methodPtr)(); // same as b->disp()
For more complicated example, check this post http://blogs.msdn.com/b/oldnewthing/archive/2004/02/06/68695.aspx. Here, if there are multiple A bases which may invoke the same B::disp, MSVC generates different entry points with each one shifting A* pointer by different offset. This is implementation-specific, of course; other compilers may choose to store the offset somewhere in vtable for example.

The rule is:
In C++ dynamic dispatch only works for member functions functions not for member variables.
For a member variable the compiler only looksup for the symbol name in that particular class or its base classes.
In case 1, the appropriate method to be called is decided by fetching the vpt, fetching the address of the appropriate method and then calling the appropiate member function.
Thus dynamic dispatch is essentially a fetch-fetch-call instead of a normal call in case of static binding.
In Case 2: The compiler only looks for x in the scope of this Obviously, it cannot find it and reports the error.

You are confused, and it seems to me that you come from more dynamic languages.
In C++, compilation and runtime are clearly isolated. A program must first be compiled and then can be run (and any of those steps may fail).
So, going backward:
<2> fails at compilation, because compilation is about static information. aptr is of type A*, thus all methods and attributes of A are accessible through this pointer. Since you declared disp() but no x, then the call to disp() compiles but there is no x.
Therefore, <2>'s failure is about semantics, and those are defined in the C++ Standard.
Getting to <1>, it works because there is a declaration of disp() in A. This guarantees the existence of the function (I would remark that you actually lie here, because you did not defined it in A).
What happens at runtime is semantically defined by the C++ Standard, but the Standard provides no implementation guidance. Most (if not all) C++ compilers will use a virtual table per class + virtual pointer per instance strategy, and your description looks correct in this case.
However this is pure runtime implementation, and the fact that it runs does not retroactively impact the fact that the program compiled.

virtual void disp(); //not necessary to define as placeholder in vtable entry will be
//overwritten when derived class's vtable entry is prepared after
//invoking Base ctor (unless we do new A instead of new B in main() below)
Your comment is not strictly correct. A virtual function is odr-used unless it is pure (the converse does not necessarily hold) which means that you must provide a definition for it. If you don't want to provide a definition for it you must make it a pure virtual function.
If you make one of these modifications then aptr->disp(); works and calls the derived class disp() because disp() in the derived class overrides the base class function. The base class function still has to exist as you are calling it through a pointer to base. x is not a member of the base class so aptr->x is not a valid expression.

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.

Why does this compile, but not link?

#include <iostream>
using namespace std;
class C
{
public:
virtual void a();
};
class D : public C
{
public:
void a() { cout<<"D::a\n"; }
void b() { cout<<"D::b\n"; }
};
int main()
{
D a;
a.b();
return 0;
}
I am getting a link error about undefined reference to 'vtable for C'. What does this mean and why is it?
I know the problem is obviously that the base class has a non-pure virtual function that is never defined, but why does this bother the linker if I am never calling it? Why is it different then any other function that I declare and don't define, that if I never call it I am fine?
I am interested in the nitty-gritty details.
Most implementations of C++ compilers generate a vtable for each class, which is a table of function pointers for the virtual functions. Like any other data item, there can only be one definition of the vtable. Some C++ compilers generate this vtable when compiling the implementation of the first declared virtual function within a type (this guarantees that there is only one definition of the vtable). If you fail to provide an implementation for the first virtual function, your compiler does not generate the vtable and the linker complains about the missing vtable with a link error.
As you can see, the precise details of this depends on the implementation of your chosen compiler and linker. Not all toolchains are the same.
Q: I know the problem is obviously that the base class has a non-pure virtual function that is never defined
A: That's the answer to your question :)
Q: Why is it different then any other function that I declare and don't define, that if I never call it I am fine?
A: Because it's not just a "function". It's a virtual class method.
SUGGESTION:
Declare three different classes:
1) a simple method
2) a virtual method (as your "C" above)
3) an abstract virtual method ( = 0)
Generate assembly output (e.g. "-S" for GCC)
Compare the three cases. Carefully note if a *constructor" is created :)
If you want C to be a pure virtual base-class, you need to tell the compiler "there will be no implementation of a()", you do this by usring ... a() = 0; to the declaration of the class. The compiler is trying to fing a base-class vtable, but there isn't one!
The need for actual function definition can arise in several circumstances. You already named one of such circumstances: the function has to be defined if you call it. However, this is not all. Consider this piece of code
void foo();
int main() {
void (*p)() = &foo;
}
This code never calls foo. However, if you try to compile it, a typical compiler will complain about missing definition of foo at linking stage. So, taking the address of a function (even if you never call it) happens to be one of the situations when the function has to be defined.
And this is where the matter of virtual functions come in. Virtual functions are typically implemented through a virtual table: a table that contains pointers to the definitions of the virtual functions. This table is formed and initialized by the compiler in advance, unconditionally, regardless of whether you actually call the functions or not. The compiler will essentially implicitly take the address of each non-pure virtual function in your program and place it into the corresponding table. For this reason, each non-pure virtual function will require a definition even if you never call it.
The exact virtual mechanism is an implementation detail, so you might end up with different specific errors is your situation (like a missing function definition or missing virtual table itself), but the fundamental reason for these error is what I described above.

In C++, does overriding an existing virtual function break ABI?

My library has two classes, a base class and a derived class. In the current version of the library the base class has a virtual function foo(), and the derived class does not override it. In the next version I'd like the derived class to override it. Does this break ABI? I know that introducing a new virtual function usually does, but this seems like a special case. My intuition is that it should be changing an offset in the vtbl, without actually changing the table's size.
Obviously since the C++ standard doesn't mandate a particular ABI this question is somewhat platform specific, but in practice what breaks and maintains ABI is similar across most compilers. I'm interested in GCC's behavior, but the more compilers people can answer for the more useful this question will be ;)
It might.
You're wrong regarding the offset. The offset in the vtable is determined already. What will happen is that the Derived class constructor will replace the function pointer at that offset with the Derived override (by switching the in-class v-pointer to a new v-table). So it is, normally, ABI compatible.
There might be an issue though, because of optimization, and especially the devirtualization of function calls.
Normally, when you call a virtual function, the compiler introduces a lookup in the vtable via the vpointer. However, if it can deduce (statically) what the exact type of the object is, it can also deduce the exact function to call and shave off the virtual lookup.
Example:
struct Base {
virtual void foo();
virtual void bar();
};
struct Derived: Base {
virtual void foo();
};
int main(int argc, char* argv[]) {
Derived d;
d.foo(); // It is necessarily Derived::foo
d.bar(); // It is necessarily Base::bar
}
And in this case... simply linking with your new library will not pick up Derived::bar.
This doesn't seem like something that could be particularly relied on in general - as you said C++ ABI is pretty tricky (even down to compiler options).
That said I think you could use g++ -fdump-class-hierarchy before and after you made the change to see if either the parent or child vtables change in structure. If they don't it's probably "fairly" safe to assume you didn't break ABI.
Yes, in some situations, adding a reimplementation of a virtual function will change the layout of the virtual function table. That is the case if you're reimplementing a virtual function from a base that isn't the first base class (multiple-inheritance):
// V1
struct A { virtual void f(); };
struct B { virtual void g(); };
struct C : A, B { virtual void h(); }; //does not reimplement f or g;
// V2
struct C : A, B {
virtual void h();
virtual void g(); //added reimplementation of g()
};
This changes the layout of C's vtable by adding an entry for g() (thanks to "Gof" for bringing this to my attention in the first place, as a comment in http://marcmutz.wordpress.com/2010/07/25/bcsc-gotcha-reimplementing-a-virtual-function/).
Also, as mentioned elsewhere, you get a problem if the class you're overriding the function in is used by users of your library in a way where the static type is equal to the dynamic type. This can be the case after you new'ed it:
MyClass * c = new MyClass;
c->myVirtualFunction(); // not actually virtual at runtime
or created it on the stack:
MyClass c;
c.myVirtualFunction(); // not actually virtual at runtime
The reason for this is an optimisation called "de-virtualisation". If the compiler can prove, at compile time, what the dynamic type of the object is, it will not emit the indirection through the virtual function table, but instead call the correct function directly.
Now, if users compiled against an old version of you library, the compiler will have inserted a call to the most-derived reimplementation of the virtual method. If, in a newer version of your library, you override this virtual function in a more-derived class, code compiled against the old library will still call the old function, whereas new code or code where the compiler could not prove the dynamic type of the object at compile time, will go through the virtual function table. So, a given instance of the class may be confronted, at runtime, with calls to the base class' function that it cannot intercept, potentially creating violations of class invariants.
My intuition is that it should be changing an offset in the vtbl, without actually changing the table's size.
Well, your intuition is clearly wrong:
either there is a new entry in the vtable for the overrider, all following entries are moved, and the table grows,
or there is no new entry, and the vtable representation does not change.
Which one is true can depends on many factors.
Anyway: do not count on it.
Caution: see In C++, does overriding an existing virtual function break ABI? for a case where this logic doesn't hold true;
In my mind Mark's suggestion to use g++ -fdump-class-hierarchy would be the winner here, right after having proper regression tests
Overriding things should not change vtable layout[1]. The vtable entries itself would be in the datasegment of the library, IMHO, so a change to it should not pose a problem.
Of course, the applications need to be relinked, otherwise there is a potential for breakage if the consumer had been using direct reference to &Derived::overriddenMethod;
I'm not sure whether a compiler would have been allowed to resolve that to &Base::overriddenMethod at all, but better safe than sorry.
[1] spelling it out: this presumes that the method was virtual to begin with!

Virtual function breaking private access

I recently came across this article on IBM site. Below is the sample code
#include "iostream"
class B {
public:
virtual void f()
{
std::cout<<"\n In class B";
}
};
class D : public B {
private:
int i;
void f()
{
std::cout<<"\n In class D i = "<<i;
}
public:
D(int i_num):i(i_num)
{}
};
int main() {
D dobj(10);
B* bptr = &dobj;
D* dptr = &dobj;
// valid, virtual B::f() is public,
// D::f() is called
bptr->f();
// error, D::f() is private
//dptr->f();
}
We are now able to call private function of D.I wanted to know doesn't this break C++ encapsulation ?
P.S. : Please go to Virtual function access section in Virtual function. I do not know why I am not getting exact link when I do paste.
The call bptr->f() is evaluated at run time depending on the type of objected pointed by bptr. At compile time the compile sees the bptr->f() call as call to B::f() and since B::f() is public the compiler doesn't report only error. It is only at runtime that actual function call D::f() is evaluated.
This doesn't break the Encapsulation principle this is a feature of C++ called Run-time Polymorphism or Dynamic Polymorphism
You cannot directly call dptr->f() because D::f() is declared under Private Access specifier and You cannot access privately declared members from outside the class.
Access-specifiers are compile-time construct, and so, the compiler detects any violation of access-rules at compile-time (obviously) based on the static type of the object (or pointer). Such violation cannot be detected at runtime.
So bptr->f() works, because the compiler sees that the static type of bptr is B which has a public function f() defined, so the expression bptr->f() passes the compiler's test. Hence it works.
But dptr->f() doesn't work, since the static type of dptr is D which has a private function f(), hence the code wouldn't even compile!
Now whether it breaks encapsulation or not, is a very subjective question and will receive subjective answers. It entirely depends on how one defines it and the arguments directly flows from it. There is no one universal definition. My personal opinion is, if the language allows it, then (it would imply that) according to the C++ community, it doesn't break encapsulation, or if it does, then C++ allows it so as to achieve something very nobel (which otherwise isn't possible). Otherwise, I would say its just yet another misfeature of C++ just like the following:
Default argument in the middle of parameter list?
It is by design.
B::f is public. User access of f via a pointer to B is allowed. Since f is virtual, the call would be dispatched to derived classes' f.
But D::f is private, you can't access f via a pointer do D.

Is a pointer to a virtual member function valid in the constructor of the base class?

My question is not about calling a virtual member function from a base class constructor, but whether the pointer to a virtual member function is valid in the base class constructor.
Given the following
class A
{
void (A::*m_pMember)();
public:
A() :
m_pMember(&A::vmember)
{
}
virtual void vmember()
{
printf("In A::vmember()\n");
}
void test()
{
(this->*m_pMember)();
}
};
class B : public A
{
public:
virtual void vmember()
{
printf("In B::vmember()\n");
}
};
int main()
{
B b;
b.test();
return 0;
}
Will this produce "In B::vmember()" for all compliant c++ compilers?
The pointer is valid, however you have to keep in mind that when a virtual function is invoked through a pointer it is always resolved in accordance with the dynamic type of the object used on the left-hand side. This means that when you invoke a virtual function from the constructor, it doesn't matter whether you invoke it directly or whether you invoke it through a pointer. In both cases the call will resolve to the type whose constructor is currently working. That's how virtual functions work, when you invoke them during object construction (or destruction).
Note also that pointers to member functions are generally not attached to specific functions at the point of initalization. If the target function is non-virtual, they one can say that the pointer points to a specific function. However, if the target function is virtual, there's no way to say where the pointer is pointing to. For example, the language specification explicitly states that when you compare (for equality) two pointers that happen to point to virtual functions, the result is unspecified.
"Valid" is a specific term when applied to pointers. Data pointers are valid when they point to an object or NULL; function pointers are valid when they point to a function or NULL, and pointers to members are valid when the point to a member or NULL.
However, from your question about actual output, I can infer that you wanted to ask something else. Let's look at your vmember function - or should I say functions? Obviously there are two function bodies. You could have made only the derived one virtual, so that too confirms that there are really two vmember functions, who both happen to be virtual.
Now, the question becomes whether when taking the address of a member function already chooses the actual function. Your implementations show that they don't, and that this only happens when the pointer is actually dereferenced.
The reason it must work this way is trivial. Taking the address of a member function does not involve an actual object, something that would be needed to resolve the virtual call. Let me show you:
namespace {
void (A::*test)() = &A::vmember;
A a;
B b;
(a.*test)();
(b.*test)();
}
When we initialize test, there is no object of type A or B at all, yet is it possible to take the address of &A::vmember. That same member pointer can then be used with two different objects. What could this produce but "In A::vmember()\n" and "In B::vmember()\n" ?
Read this article for an in-depth discussion of member function pointers and how to use them. This should answer all your questions.
I have found a little explanation on the Old New Thing (a blog by Raymond Chen, sometimes referred to as Microsoft's Chuck Norris).
Of course it says nothing about the compliance, but it explains why:
B b;
b.A::vmember(); // [1]
(b.*&A::vmember)(); // [2]
1 and 2 actually invoke a different function... which is quite surprising, really. It also means that you can't actually prevent the runtime dispatch using a pointer to member function :/
I think no. Pointer to virtual member function is resolved via VMT, so the same way as call to this function would happen. It means that it is not valid, since VMT is populated after constructor finished.
IMO it is implementation defined to take address of a virtual function. This is because virtual functions are implemented using vtables which are compiler implementation specific. Since the vtable is not guaranteed to be complete until the execution of the class ctor is done, a pointer to an entry in such a table (virtual function) may be implementation defined behavior.
There is a somewhat related question that I asked on SO here few months back; which basically says taking address of the virtual function is not specified in the C++ standard.
So, in any case even if it works for you, the solution will not be portable.