COMP2006 Lecture 10 Function Pointers Virtual Functions and Vtables
COMP2006 Lecture 10 Function Pointers Virtual Functions and Vtables
C++ Programming
Lecture 10
Dr Chao Chen
1
This lecture
• Function pointers
2
Function pointers
3
Process structure in memory
Stack
Data area that grows downwards towards the heap
LIFO data structure, for local variables and parameters
Heap
Data area that grows upwards towards stack
Specially allocated memory (malloc, free, …, probably new, delete)
Data and BSS (uninitialised data) segment
Read-only: Constants String literals
Read/write: Global variables Static local variables
printf("Test 1: " );
g1 = &f1;
(*g1)();
g1(); // Short way
printf("\nTest 2: " );
g2 = &f2;
(*g2)();
g2(); // Short way 6
Simplest functions… 2/2
void f1() { printf( "f1(); " ); }
void f2() { printf( "f2(); " ); }
int main()
{
void (*g1)() = NULL; g1 and g2 are function pointers
void (*g2)() = NULL;
of type void function()
printf("Test 1: " ); Initialised to NULL
g1 = &f1;
(*g1)();
Make g1 point at f1()
g1(); // Short way
Note: The & is optional.
printf("\nTest 2: " );
g2 = &f2;
As for arrays, function
(*g2)(); name is a pointer to it
g2(); // Short way 7
Simplest functions… output
void f1() { printf( "f1(); " ); }
void f2() { printf( "f2(); " ); }
int main()
{
void (*g1)() = NULL;
void (*g2)() = NULL;
printf("Test 1: " );
g1 = &f1;
(*g1)();
g1(); // Short way Test 1: f1(); f1();
printf("\nTest 2: " );
g2 = &f2;
(*g2)(); Test 2: f2(); f2();
g2(); // Short way 8
Assignment of pointers
void f1() { printf( "f1(); " ); }
void f2() { printf( "f2(); " ); }
int main()
{
void (*g1)() = NULL;
void (*g2)() = NULL;
g1 = &f1;
g2 = &f2;
int main()
{
void (*g1)() = NULL;
void (*g2)() = NULL;
g1 = &f1;
g2 = &f2;
printf("\nTest 4: " );
g3 = &f3;
g4 = &f4;
printf( "Result = %d ", g3() );
printf( "Result = %d ", g4() ); 11
Returning values : output
int f3() { printf( "f3(); " ); return 3; }
int f4() { printf( "f4(); " ); return 4; }
int main()
{
int (*g3)() = NULL;
int (*g4)() = NULL;
Test 4:
printf("\nTest 4: " );
f3(); Result = 3
g3 = &f3; f4(); Result = 4
g4 = &f4;
printf( "Result = %d ", g3() );
printf( "Result = %d ", g4() ); 12
Passing parameters
int f3() { printf( "f3(); " ); return 3; }
int main()
{
int (*g3)() = &f3;
int (*g5)( int ) = &f5; Look here
int (*g6)( int ) = &f6;
/* Usage: */
fptr1 f= …;
fptr2 g= … , myfptr = …; 18
Arrays of function pointers
#include <cstdio> int main()
{
int f1( int i ) int i,j,k;
{ return i; }
int f2( int i ) fptr fptrarray[6];
{ return i*2; } fptrarray[0] = &f1;
int f3( int i ) fptrarray[1] = &f2;
{ return i*3; } fptrarray[2] = &f3;
20
Example: virtual functions
class BaseClass
{
public: char* foo() { return "BaseFoo"; }
virtual char* bar() { return "BaseBar"; }
};
int main()
{
SubClass* pSub = new SubClass;
BaseClass* pSubAsBase = pSub;
printf( "pSubAsBase->foo() %s\n", pSubAsBase->foo() );
printf( "pSubAsBase->bar() %s\n", pSubAsBase->bar() );
delete pSub; 21
}
Virtual and non-virtual functions
• For normal/default (non-virtual) functions:
– Type of pointer determines function to call
– i.e. the apparent type of the object, from pointer type
– Use the type of the object the compiler thinks it is:
• Type of pointer (or reference) to the object
• Type of the member function making the call (hidden this ptr)
• Easier for the compiler, type is known at compile-time
• Virtual function:
– Finds out the actual function to call based upon the
object type AT RUNTIME - much more difficult - slower
– i.e. look-up table: ‘which function should I really call’
– Works in the same way as Java functions
22
Possible Implementation
• How could virtual functions be implemented?
25
Example (2/8)
class Base Base:
{ f1()
public: f2()
virtual void f1(); f3()
virtual void f2();
virtual void f3();
void f4();
}
26
Example (3/8)
class Sub1 : public Base Base:
{ f1()
public: f2()
f3()
virtual void f2();
void f5(); Sub1:
virtual void f6(); ?
}
27
Example (4/8)
class Sub1 : public Base Base:
{ f1()
public: f2()
f3()
virtual void f2();
void f5(); Sub1:
virtual void f6(); f1()
} f2()
f3()
f6()
28
Example (5/8)
class Sub2 : public Sub1 Base:
{ f1()
public: f2()
virtual void f1(); f3()
virtual void f2();
} Sub1:
Sub2: f1()
? f2()
f3()
f6()
29
Example (6/8)
class Sub2 : public Sub1 Base:
{ f1()
public: f2()
virtual void f1(); f3()
virtual void f2();
} Sub1:
Sub2: f1()
f1() f2()
f2() f3()
f3() f6()
f6() 30
Example (7/8)
class Sub3 : public Sub2 Base:
{ f1()
public: f2()
virtual void f7(); f3()
virtual void f8();
void f9(); Sub1:
} Sub2: f1()
Sub3:
f1() f2()
?
f2() f3()
f3() f6()
f6() 31
Example (8/8)
class Sub3 : public Sub2 Base:
{ f1()
public: f2()
virtual void f7(); f3()
virtual void f8();
Sub3:
f1() void f9(); Sub1:
}
f2() Sub2: f1()
f3() f1() f2()
f6() f2() f3()
f7() f3() f6()
f8() f6() 32
Final comments and special
cases
33
Virtualness is inherited in C++
• virtual-ness is inherited
– If a function is virtual in the base class then
the function is virtual in the derived class(es)
• Including destructor! (If virtual in base class then
destructors of derived classes are virtual)
– Even when the keyword virtual is not used in
the derived class
• All functions in Java are virtual by default
– Unless you make them ‘final’
– Java, final functions are different: they cannot
be re-implemented in sub-classes
34
sizeof()
• Member Functions act on objects of the class type
– Even member functions
• Member Functions are not actually in the objects
– The functions just have a hidden ‘this’ parameter saying which
object they apply to
– The hidden ‘this’ parameter and permission to access private
members are the ONLY things special about member functions
• The object is the collection of data
– But also includes any hidden data and pointers that the
compiler adds to implement features (e.g. vtable)
• Adding a member function to an existing class will not
usually make the objects bigger
• Exception: adding the first virtual function may add a
vtable pointer (or equivalent)
35
– Understand why this is the case!
Should a function be virtual?
• If member function is called from a base class
function or through a base class pointer
AND the behaviour should depend on class type
of the object
then the member function has to be virtual
– Otherwise when it is called by the base class, or
through a base-class pointer, the base-class version
will be called, not your modified version
• Utility functions will often not be virtual
– When functionality is not expected to be changed in
sub-classes
– Faster to call these functions – no look-up needed
– Makes it easier for function to be inline, which can
make code even faster: no function call needed 36
What to know
• Some equivalent of a vpointer exists in
objects with virtual functions
– Just one pointer is needed in each object
• Only virtual functions appear in vtables
– No need to record non-virtual functions
• Looking up which function to call is slower than
calling a non-virtual function
1. Go to the object itself
2. Go to the vtable (following the vpointer)
3. Look up which function to call
4. Call the function
37
Next lecture
• Automatically created methods:
– Default Constructor
– Copy Constructor
– Assignment operator
– Destructor
• Conversion constructors
• Conversion operators
• Friends
38