questions:
in the code below, the 'this' pointer points to different things in base and derived classes, even though it technically contains the same address. why is that.
what is happening when the 'this' pointer is used with inheritance.
(any help would be appreciated. thanks.)
#include <iostream>
using namespace std;
// this pointer and inheritance.
class base {
public:
int x;
base() {
x = 10;
}
void func() {
cout<< this->x << endl; // 10
cout<< this << endl;
}
};
class derived : public base {
public:
int x;
derived() {
x = 20;
}
void func() {
cout<< this->x << endl; // 20
cout<< this << endl;
base::func();
}
};
int main () {
derived d;
d.func();
cout<< "execution complete.\n";
return 0;
}
output:
20
0x61ff18
10
0x61ff18
execution complete.
in the code below, the 'this' pointer points to different things in base and derived classes, even though it technically contains the same address. why is that.
Classes contain subobjects. They can be base-subobjects or non-static data members. The first sub-object can share the memory address of the encapsulating complete object:
|derived | < complete object
|base|x | < sub objects of derived
|x | < sub objects of base sub object
^
|
same address
what is happening when the 'this' pointer is used with inheritance.
If you call a non-static member function of a class, this points to the instance argument within that function.
If you call a non-virtual non-static member function of a base of a derived object, this will point to the base sub object within that function.
If you call a virtual non-static member function of a class using unqualified lookup, it will call the most derived override of that function and this within that function will point to the object where that function is derived.
Your class derived contains two integers. They have the names:
this->base::x
and
this->derived::x
What you seem to be discovering is that you can simply type this->x to refer to one of those integers.
The compiler will decide which x you are referring to by context. Inside the base class, you must mean this->base::x. Inside the derived class, it is assumed that you mean this->derived::x and you would need to explicitly write this->base::x to tell the compiler that you are referring to the int x; defined in base.
the 'this' pointer points to different things in base and derived classes
That is not true.
this does not point to different things in base and derived. It is the same this.
The meaning of this->x changes, because your class has two variables both named x.
The derived class in your program has a member function named func that hides the inherited member function with the same name from base. Similarly, the derived class also a data member named x that hides the inherited data member with the same name from base.
Now, when you wrote:
d.func(); //this calls the derived class member function `func` implicitly passing the address of `d` to the implicit `this` parameter
In the above call, you're calling the derived class' member function func meanwhile implicitly passing the address of d to the implicit this parameter. The type of this inside func of derived is derived*.
Now, inside the member function func of derived the expression this->x uses the data member x of the derived class(and not the inherited member x) because as explained above, it hides the inherited member from base. Thus we get the output 20.
Next, cout<< this << endl; just prints this.
Next, the call expression base::func() is encountered. Also note that base::func() is equivalent to writing this->base::func(). This has the effect that it calls the inherited member function named func that was hidden due to the derived class having a function with the same name. Note in this call also, the same address is passed to the implicit this parameter of func of base class. The difference this time is that, this inside base's member function func is of type base*.
Now, inside the member function func of base, the x in the expression this->x refers to the base class' data member x and hence prints the value 10. Thus we get the output 10.
Finally, we have cout<< this << endl; inside base's member function func, which just prints the this.
Related
The code below works, but I'm not quite sure I understand why the member function pointer memfunc_ptr ends up pointing to the correct function Derived::member_func() (see example here). I know that a member function pointer defines an offset into the class of the object, for which it's defined, in this case class Base. So, to justify the result obtained by the code, i.e., that the member function Derived::member_func is called, instead of Base::member_func, I have to conclude that this offset is applied to the vtable of the class Derived, as member_func() is virtual, and the object d is of class Derived. Does that make sense?
#include <iostream>
class Base {
public:
virtual void member_func() {
std::cout << "Base" << '\n'; };
};
class Derived : public Base {
public:
virtual void member_func() { std::cout << "Derived" << '\n'; };
};
int main() {
typedef void (Base::*MFP)();
MFP memfunc_ptr;
memfunc_ptr = &Base::member_func;
Derived d;
(d.*memfunc_ptr)();
}
member_func() is a virtual function. The compiler will hence always call the most appropriate function for the real type of the object that is pointed to. The way this is ensured is implementation specific.
The most frequently way to do it is to use a vtable, a table of funtion pointers. A pointer to the vtable is initialised during the construction of the object. Every time you refer to such a virtual function, the compiler will generate code to find the function pointer in the vtable (using an ofset in the vtable). And when you use a pointer to a virtual function, the compiler will generate code to find the right pointer in the vtable.
This article will show you how this work with more details.
Say there was no Hello function and we simply called ob.display in main then it calls the display function of class B and not class A.
Call of the function display() is being set once by the compiler as the version defined in the base class. This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. This is also sometimes called early binding because the display() function is set during the compilation of the program.
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
Now in this program, Passing the object as call by value,call by pointer and call by reference to the Hello function works fine. Now if we use Polymorphism and want to display the member function of the derived class if it is called we have to add the virtual keyword before display function in the base. If we pass the object value by call by pointer and call by reference it call the function in the derived class but if we pass the object by value it doesn't why is it so?>
class A
{
public:
void display(); // virtual void display()
{
cout << "Hey from A" <<endl;
}
};
class B : public A
{
public:
void display()
{
cout << "Hey from B" <<endl;
}
};
void Hello(A ob) // &ob //*ob
{
ob.display(); // ob->display()
}
int main()
{
B obj;
Hello(obj); // obj //&ob
return 0;
}
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
A non-virtual function is simply resolved by the compiler, according to the static type of the object (or reference or pointer) it's called on. So given an object of the derived type, and a reference to its sub-object:
B b;
A & a = b;
you'd get different results from calling a non-virtual function:
b.display(); // called as B
a.display(); // called as A
If you know the real type, then you could specify that you want to call that version:
static_cast<B&>(a).display(); // called as B
but that would go horribly wrong if the object that a refers to doesn't have type B.
Now if we use Polymorphism and want to display the member function of the derived class if it is called we have to add the virtual keyword before display function in the base.
Correct. If you make the function virtual, then it's resolved at runtime according to the dynamic type of the object, even if you use a different type of reference or pointer to access it. So both the above examples would call it as B.
If we pass the object value by call by pointer and call by reference it call the function in the derived class but if we pass the object by value it doesn't why is it so?
If you pass it by value, then you're slicing it: copying just the A part of the object, to make a new object of type A. So, whether or not the function is virtual, calling it on that object would choose the A version, since it's an A and nothing but an A.
If you pass by reference or pointer, then you're still accessing the original object, with its dynamic type B. So the virtual function call would resolve to the B version.
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
You can provide a templated base class like this
template<typename Derived>
class A {
public:
void display() {
// call Derived first
static_cast<Derived*>(this)->display();
cout << "Hey from A" <<endl;
}
};
class B : public A<B> {
public:
void display() {
cout << "Hey from B" <<endl;
}
};
This is a well known pattern, called CRTP and Static Polymorphism.
I have a question regarding what "this" points in derived classes in C++.
class A
{
int a;
public:
void funca() { cout << this << endl; }
};
class B
{
int b;
public:
void funcb() { cout << this << endl; }
};
class Derived : public A, public B {};
int main() {
Derived d;
d.funca();
d.funcb(); // prints 4bytes more than the above.
}
In this case, how are "this" in base classes interpreted in the derived class?
Is it this of the derived class or this of the base class??
From the output, I think this points to the class object where it is used. Am I right?
how are "this" in base classes interpreted in the derived class?
I guess the question should be How base classes resides in derived classes
When a class is inherited by another, the compiler kind of places the members of base class in the derived class. The this always refers to the actual object, you are right about this. d.funcb(); prints 2 bytes ahead because, members of B starts after 4 bytes of A in Derived. This 4 bytes is taken by A::a member variable. But the layout and memory model is not guaranteed, and varies depending on compiler. One possible memory layout for Derived may be
Members of A (4 byte in this case for a)
Members of B (4 byte in this case for b)
Members of Derived (if any)
So derived class does not have a Base class "this", there is only one this, which refer to the actual object. And derived classes get copy of base class members in them.
Class Derived contains two subobjects A and B. These subobjects have non-static member functions. The first implicit argument of these functions is the poinetr that points to the corresponding object.
So in your example when function funca is called it gets the pointer that points to subobject A inside class Derived. The same way when function funcb is called it gets the pointer that points to subobject B inside class Derived.
Shotly speaking in each class definition this denotes an object of the defined class. In the class definition of class A this denotes an object of class A. In the class definition of class B this denotes an object of class B. Inside class Derived subobjects A and B have different locations i.e. different addresses. So the output in your example will differ.
Here's a piece of code I had written to see the behaviour during downcasting.
#include <iostream>
using namespace std;
class base {
public :
void function()
{
cout << "\nInside class Base";
}
};
class derived : public base {
public :
void function()
{
cout << "\nInside class Derived.";
}
};
int main()
{
base * b1 = new base();
base * b2 = new derived();
derived * b3 = (derived*)b1 ;
b1 -> function();
b2 -> function();
b3 -> function(); // print statement 3
static_cast<derived*>(b2) -> function();
static_cast<derived*>(b1) -> function(); // print statement 5
return 0;
}
The output is as follows .
Inside class Base
Inside class Base
Inside class Derived.
Inside class Derived.
Inside class Derived.
I feel print statement 3 and print statement 5 should have displayed "Inside class base" .
Can someone please explain what I might be missing here?
Both are cases of undefined behavior. Casting b1 to derived* is not valid.
However, if you said base* b1 = new derived(), you would have the same behavior. Since neither function is marked virtual, then it only checks objects type at compile time.
So the first case would print "Inside class Base", even though its actually a derived pointer.
You need to define base method void function() as virtual:
virtual void function()
{
cout << "\nInside class Base";
}
and resulting output is:
Inside class Base
Inside class Derived.
Inside class Base
Inside class Derived.
Inside class Base
In OP, 5th case may not be an undefined behaviour as stated in the reference1 and inline member function memory is not stored like data members as stated here insuring that after static cast to derived type, derived member function is called:
The inverse of any standard conversion sequence (Clause 4) not
containing an lvalue-to-rvalue (4.1), array-to- pointer (4.2),
function-to-pointer (4.3), null pointer (4.10), null member pointer
(4.11), or boolean (4.12) conversion, can be performed explicitly
using static_cast.
1 Working Draft, Standard for Programming Language C++, 5.2.9 Static Cast - 7
The functions are dispatched at compilation time, based solely on the static type, as they are not virtual.
Static type of b3 in print statement is Derived *, hence 'Inside class Derived'. Print statement 5 casts Base * to Derived *, hence the same printout.
Add virtual to function() definition in Base and check again to see what happens.
That's the expected behavior.
Non virtual methods are called by the object's type at compile time.
You used a static cast, so the compiler treats it as "Derived" class.
If you'd declare the method as virtual then it will create a virtual look up table for the function, and call the method according to the actual run-time type.
In C++, can member function pointers be used to point to derived (or even base) class members?
EDIT:
Perhaps an example will help. Suppose we have a hierarchy of three classes X, Y, Z in order of inheritance.
Y therefore has a base class X and a derived class Z.
Now we can define a member function pointer p for class Y. This is written as:
void (Y::*p)();
(For simplicity, I'll assume we're only interested in functions with the signature void f() )
This pointer p can now be used to point to member functions of class Y.
This question (two questions, really) is then:
Can p be used to point to a function in the derived class Z?
Can p be used to point to a function in the base class X?
C++03 std, §4.11 2 Pointer to member conversions:
An rvalue of type “pointer to member of B of type cv T,” where B is a class type, can be converted to an rvalue of type “pointer to member of D of type cv T,” where D is a derived class (clause 10) of B. If B is an inaccessible (clause 11), ambiguous (10.2) or virtual (10.1) base class of D, a program that necessitates this conversion is ill-formed. The result of the conversion refers to the same member as the pointer to member before the conversion took place, but it refers to the base class member as if it were a member of the derived class. The result refers to the member in D’s instance of B. Since the result has type “pointer to member of D of type cv T,” it can be dereferenced with a D object. The result is the same as if the pointer to member of B were dereferenced with the B sub-object of D. The null member pointer value is converted to the null member pointer value of the destination type. 52)
52)The rule for conversion of pointers to members (from pointer to member of base to pointer to member of derived) appears inverted compared to the rule for pointers to objects (from pointer to derived to pointer to base) (4.10, clause 10). This inversion is necessary to ensure type safety. Note that a pointer to member is not a pointer to object or a pointer to function and the rules for conversions of such pointers do not apply to pointers to members. In particular, a pointer to member cannot be converted to a void*.
In short, you can convert a pointer to a member of an accessible, non-virtual base class to a pointer to a member of a derived class as long as the member isn't ambiguous.
class A {
public:
void foo();
};
class B : public A {};
class C {
public:
void bar();
};
class D {
public:
void baz();
};
class E : public A, public B, private C, public virtual D {
public:
typedef void (E::*member)();
};
class F:public E {
public:
void bam();
};
...
int main() {
E::member mbr;
mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
mbr = &C::bar; // invalid: C is private
mbr = &D::baz; // invalid: D is virtual
mbr = &F::bam; // invalid: conversion isn't defined by the standard
...
Conversion in the other direction (via static_cast) is governed by § 5.2.9 9:
An rvalue of type "pointer to member of D of type cv1 T" can be converted to an rvalue of type "pointer to member of B of type cv2 T", where B is a base class (clause 10 class.derived) of D, if a valid standard conversion from "pointer to member of B of type T" to "pointer to member of D of type T" exists (4.11 conv.mem), and cv2 is the same cv-qualification as, or greater cv-qualification than, cv1.11) The null member pointer value (4.11 conv.mem) is converted to the null member pointer value of the destination type. If class B contains the original member, or is a base or derived class of the class containing the original member, the resulting pointer to member points to the original member. Otherwise, the result of the cast is undefined. [Note: although class B need not contain the original member, the dynamic type of the object on which the pointer to member is dereferenced must contain the original member; see 5.5 expr.mptr.oper.]
11) Function types (including those used in pointer to member function
types) are never cv-qualified; see 8.3.5 dcl.fct.
In short, you can convert from a derived D::* to a base B::* if you can convert from a B::* to a D::*, though you can only use the B::* on objects that are of type D or are descended from D.
I'm not 100% sure what you are asking, but here is an example that works with virtual functions:
#include <iostream>
using namespace std;
class A {
public:
virtual void foo() { cout << "A::foo\n"; }
};
class B : public A {
public:
virtual void foo() { cout << "B::foo\n"; }
};
int main()
{
void (A::*bar)() = &A::foo;
(A().*bar)();
(B().*bar)();
return 0;
}
The critical issue with pointers to members is that they can be applied to any reference or pointer to a class of the correct type. This means that because Z is derived from Y a pointer (or reference) of type pointer (or reference) to Y may actually point (or refer) to the base class sub-object of Z or any other class derived from Y.
void (Y::*p)() = &Z::z_fn; // illegal
This means that anything assigned to a pointer to member of Y must actually work with any Y. If it was allowed to point to a member of Z (that wasn't a member of Y) then it would be possible to call a member function of Z on some thing that wasn't actually a Z.
On the other hand, any pointer to member of Y also points the member of Z (inheritance means that Z has all the attributes and methods of its base) is it is legal to convert a pointer to member of Y to a pointer to member of Z. This is inherently safe.
void (Y::*p)() = &Y::y_fn;
void (Z::*q)() = p; // legal and safe
You might want to check out this article Member Function Pointers and the Fastest Possible C++ Delegates The short answer seems to be yes, in some cases.
I believe so. Since the function pointer uses the signature to identify itself, the base/derived behavior would rely on whatever object you called it on.
My experimentation revealed the following: Warning - this might be undefined behaviour. It would be helpful if someone could provide a definitive reference.
This worked, but required a cast when assigning the derived member function to p.
This also worked, but required extra casts when dereferencing p.
If we're feeling really ambitious we could ask if p can be used to point to member functions of unrelated classes. I didn't try it, but the FastDelegate page linked in dagorym's answer suggests it's possible.
In conclusion, I'll try to avoid using member function pointers in this way. Passages like the following don't inspire confidence:
Casting between member function
pointers is an extremely murky area.
During the standardization of C++,
there was a lot of discussion about
whether you should be able to cast a
member function pointer from one class
to a member function pointer of a base
or derived class, and whether you
could cast between unrelated classes.
By the time the standards committee
made up their mind, different compiler
vendors had already made
implementation decisions which had
locked them into different answers to
these questions. [FastDelegate article]
Assume that we have class X, class Y : public X, and class Z : public Y
You should be able to assign methods for both X, Y to pointers of type void (Y::*p)() but not methods for Z. To see why consider the following:
void (Y::*p)() = &Z::func; // we pretend this is legal
Y * y = new Y; // clearly legal
(y->*p)(); // okay, follows the rules, but what would this mean?
By allowing that assignment we permit the invocation of a method for Z on a Y object which could lead to who knows what. You can make it all work by casting the pointers but that is not safe or guaranteed to work.
Here is an example of what works.
You can override a method in derived class, and another method of base class that uses pointer to this overridden method indeed calls the derived class's method.
#include <iostream>
#include <string>
using namespace std;
class A {
public:
virtual void traverse(string arg) {
find(&A::visit, arg);
}
protected:
virtual void find(void (A::*method)(string arg), string arg) {
(this->*method)(arg);
}
virtual void visit(string arg) {
cout << "A::visit, arg:" << arg << endl;
}
};
class B : public A {
protected:
virtual void visit(string arg) {
cout << "B::visit, arg:" << arg << endl;
}
};
int main()
{
A a;
B b;
a.traverse("one");
b.traverse("two");
return 0;
}