Assuming I have this class:
class Shape
{
public:
int value;
Shape(int v) : value(v) {};
void draw()
{
cout << "Drawn the element with id: " << value << endl;
}
};
and the following code (which works)
Shape *myShapeObject = new Shape(22);
void (Shape::*drawpntr)();
drawpntr = &Shape::draw;
(myShapeObject ->*drawpntr)();
I have a drawpntr function pointer to a void-returning 0-arguments function member of the class Shape.
First thing I'd like to ask:
drawpntr = &Shape::draw;
the function is a member function and there's no object here.. what address does drawpntr receive? The class shouldn't even exist
I agree with the line
(myShapeObject->*drawpntr)();
because I understand I cannot de-reference a function pointer to a member function (no object -> no function), but what address is actually stored in drawpntr?? There's no object when the
drawpntr = &Shape::draw;
line is invoked.. and the class shouldn't exist either as an entity
All member functions share the same code, so they have the same address in the code segment of memory. Member functions operate on different instances only because they are implicitly passed different values of this pointer. They are not tied in any way to any of the instances on which they operate. The actual value of drawpntr could be determined statically if the function is non-virtual, or dynamically (through the vtable) if the function is virtual.
Related
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.
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.
I have created simple object containing integer and few methods, integer primitive variable alone and compare their sizes. "sizeof()" for both returned value of "4". Why is that - shouldn't object that is composite type and contains information about methods take more space?
#include <iostream>
class Person{
private:
int a;
public:
void hello(){
std::cout << "hello";
}
void DoSomething(){
a++;
}
};
int main(){
int a;
Person p;
std::cout << sizeof(a) << std::endl;
std::cout << sizeof(p) << std::endl;
return 0;
}
The methods (technically member functions in C++ terminology) do not contribute to the "size" of an object. If you think about it, it makes sense. A member function is applicable to any object instantiated from the class or its descendants, and is in a sense independent of the instance. You can think of the member function of some fictive class Foo as being a standalone function declared as
return_type some_member_function(Foo* ptr, /* other params */){...}
where the first parameter is a pointer to the instance you are applying the function to. The compiler actually passes the pointer ptr implicitly when calling the member function, so
foo.some_member_function(/* other params */)
is being translated internally as
some_member_function(&foo, /* other params */)
You can use the address of the current instance pointed by ptr in actual C++ code via the keyword this. Technically the keyword this is a prvalue expression whose value is the address of the object, on which the member function is being called.
PS: as #greyfade mentioned in the comment, the size of an object may be increased by a mere declaration of virtual member function(s), since in this case the compiler must store internally a pointer to the so called "virtual table". This is the case no matter if the virtual function is being overridden or not. So, if you care about object size, don't blindly make the destructor virtual, unless you plan to use your class as the base in a hierarchy.
Let's say I have 2 classes Instrument and Brass, where Brass is derived from Instrument:
class Instrument
{
protected:
std::string _sound;
public:
Instrument(std::string sound) : _sound(sound) {}
virtual void play() { std::cout << _sound << std::endl; }
};
class Brass : public Instrument
{
private:
std::string _pitchShifter;
public:
Brass(std::string pitchShifter) : Instrument("braaaaaa"), _pitchShifter(pitchShifter)
{}
void printPitchShifter() { std::cout << _pitchShifter << std::endl; }
}
For some crazy reason I have a pointer to a member function of Instrument:
typedef void(Instrument::*instrumentVoidFunc)() //declaring member function pointers is too damn confusing
instrumentVoidFunc instrumentAction;
Now obviously, this will work, with well-defined behaviour:
Instrument soundMaker("bang!");
instrumentAction = &Instrument::play;
(soundMaker.*instrumentAction)();
And the output should be bang!.
But I can also make instrumentAction point to a Brass member function not present in Instrument by upcasting it, like so:
instrumentAction = static_cast<instrumentVoidFunc>(&Brass::printPitchShifter);
My understanding is (or was, anyway) that upcasting the member function pointer should destroy any ability for it to refer to derived class functions that aren't already present in the base class. However:
Brass trumpet("valves");
(trumpet.*instrumentAction)();
...prints out valves just as if I had called the function on the derived class normally. So apparently upcasting a derived class function pointer does not affect what happens when it is dereferenced on a derived class (though dereferencing it on a base class gives undefined behaviour).
How exactly does the compiler make this possible?
Although function pointer casts are possible, calling a function through a function type which doesn't match the original type is undefined behavior. The reason function pointer casts are allowed is to support casting to and storing a common type but recovering the correct by casting the function pointer back before calling it. The basic background for this restriction is that even compatible pointers may require adjustment upon use. Hiding the correct signature would imply a suitable trampoline to exist (i.e., the function pointer would need to have additional state).
The paragraph below was extracted from page 420 from Stroustup book "The C++ Programming Language" (third edition):
Because a pointer to a virtual member (s in this example) is a kind of
offset, it does not depend on an object’s location in memory. A
pointer to a virtual member can therefore safely be passed between
different address spaces as long as the same object layout is used in
both. Like pointers to ordinary functions, pointers to nonvirtual
member functions cannot be exchanged between address spaces.
I'm disputing the last sentence in this paragraph. Below, you'll find a code snippet where pointers to nonvirtual member functions, foo() and foo1(), are exchanged between one base object a and a derived object b, without a problem.
What cannot be done is the overloading, of any of the functions in the base, foo() or foo1(), in the derived class, for in this case the compiler will emit an error as shown below.
#include <iostream>
class A
{
int i;
public:
A() : i(1) {}
void foo() { std::cout << i << '\n'; }
void foo1() { std::cout << 2 * i << '\n'; }
};
class B: public A
{
int j;
public:
B() : A(), j(2) {}
// void foo() { std::cout << j << '\n'; }
};
int main()
{
typedef void (A::* PMF)();
PMF p = &B::foo; // error C2374: 'p' redefinition, multiple initialization
// if foo() is overloaded in B.
PMF q = &B::foo1;
B b;
(b.*p)();
(b.*q)();
A a;
(a.*p)();
(a.*q)();
}
That sentence is correct: In (standard) C++, a program, or rather process, has exactly one address space. So as ulidtko pointed out, this sentence is referring to the possibilities of exchanging pointers to virtual vs. non-virtual member functions between address spaces of different processes.
A non-virtual member function of a class is pretty much a standard function with an implicit argument to the object you call it for (the this pointer). As such, it gets assigned some address in your process's address space on loading. Where exactly it ends up in your address space is certainly depending on your platform and whether or not that member function is part of a dynamically linked library. The point is, for two processes it is not necessarily the same address. So passing a pointer to and then executing such a function in another process will potentially 'set your machine on fire (TM)'.
A virtual member function is still pretty much the same as the non-virtual member function as in 'some address in memory you jump to on execution and pass it your this pointer', but it gets called through the virtual function table (vtable) instead of directly. So a pointer to a virtual member function is pretty much just an index into your object's virtual function table. Calling that function does then something along the lines of 'taking your object pointer, maybe increment the pointer to get to the object's vtable and jump to the address at the given index of that table, passing the address of the object itself as the this pointer'. So this indirection via the vtable makes exchanging the pointer to the virtual member function between address spaces work.
Disclaimer: I am leaning somewhat over my "I really know what I am talking about"-comfort zone here. So in case I oversimplified something or worse, yet, engaged in distributing false information, feel free to shred my answer apart ;).
A pointer will always exist as a virtual memory so it is correct, you can check the address and will see there is no physical pointer to the memory address
Because a pointer to a virtual member (s in this example) is a kind of offset, it does not depend on an object’s location in memory. A pointer to a virtual member can therefore safely be passed between different address spaces as long as the same object layout is used in both. Like pointers to ordinary functions, pointers to nonvirtual member functions cannot be exchanged between address spaces.