============================================Begin
=====================================
接着上篇博客介绍。继续讨论分析类对象在内存中分配布局,这篇博客主要介绍有虚函数时类对象在内存中的分配和布局。
“能量补充":使用虚函数,系统要有一定的空间开销。当一个类声明了虚函数时,编译器会为该类构造一个虚函数表(
virtual function table, 简称vtalbe),它是一个指针数组,每个元素存放虚函数的入口地址。类对象本身只存放了一个指向虚函
数表的指针。
=============================================================================================
(4)带有虚函数的类对象的内存分布
#include<iostream>
#include<cstring>
using namespace std;
class Student{
public:
char* _sname;
int _sid;
protected:
int _sage;
private:
int _score;
public:
Student(int, char*, int, int);
~Student();
virtual void Display();
virtual void ClassType();
virtual void FunctionStudent();
};
Student::Student(int sid, char* sname, int sage, int score)
:_sid(sid), _sage(sage), _score(score){
int len = strlen(sname)+1;
this->_sname = new char[len];
strcpy(this->_sname, sname);
}
Student::~Student(){
delete[] this->_sname;
}
void Student::Display(){
cout << "SID = "<<this->_sid<<endl;
cout << "SName = "<<this->_sname<<endl;
cout << "SAge = "<<this->_sage<<endl;
cout << "Score = "<<this->_score<<endl;
}
void Student::ClassType(){
cout << "This is Student Class"<<endl;
}
void Student::FunctionStudent(){
cout << "Student::FunctionStudent()"<<endl;
}
int main(void){
Student stu(100, (char*)"s_river", 22, 60);
Student* pstu = &stu;
pstu->Display();
pstu->ClassType();
pstu->FunctionStudent();
cout << "sizeof(Student) = " << sizeof(stu) << " sizeof(Student*) = " << sizeof(pstu) << endl;
return 0;
}
(5)带有虚函数继承的类对象的内存分布
class Graduate : public Student{
private:
int _salary;
public:
char* _addr;
public:
Graduate(int, char*, int, int,
int, char*);
~Graduate();
virtual void Display();
virtual void ClassType();
virtual void FunctionGraduate();
};
Graduate::Graduate(int sid, char* sname, int sage, int score,
int salary, char* addr)
:Student(sid,sname,sage, score),
_salary(salary){
int len = strlen(addr)+1;
this->_addr = new char[len];
strcpy(this->_addr, addr);
}
Graduate::~Graduate(){
delete[] this->_addr;
}
void Graduate::Display(){
cout << "SID = "<<this->_sid<<endl;
cout << "SName = "<<this->_sname<<endl;
cout << "SAge = "<<this->_sage<<endl;
//cout << "Score = "<<this->_score<<endl;
cout << "Salary = " << this->_salary << endl;
cout << "Address = " << this->_addr << endl;
}
void Graduate::ClassType(){
cout << "This is Graduate Class" << endl;
}
void Graduate::FunctionGraduate(){
cout << "Graduate::FunctionGraduate()" << endl;
}
int main(void){
Student stu(100, (char*)"s_river", 22, 60);
Graduate grt(100, (char*)"g_s_river", 22, 60, 10001, (char*)"Wuhan");
Student* pstu = &stu;
Graduate* pgrt = &grt;
pstu->Display();
pstu->ClassType();
pstu->FunctionStudent();
pgrt->Display();
pgrt->ClassType();
pgrt->FunctionGraduate();
cout << "sizeof(Student) = " << sizeof(stu) << " sizeof(Student*) = " << sizeof(pstu) << endl;
cout << "sizeof(Graduate) = " << sizeof(grt) << " sizeof(Graduate*) = "<<sizeof(pgrt) << endl;
<span style="color:#ff0000;"> pstu = &grt;</span>
pstu->Display();
pstu->ClassType();
pstu->FunctionStudent();
return 0;
}
(6)带有虚函数的多重继承类对象内存分布
class Graduate : public Student, public Teacher{
private:
int _salary;
public:
char* _addr;
public:
Graduate(int, char*, int, int,
int, char*, char*,
int, char*);
~Graduate();
virtual void Display();
virtual void ClassType();
virtual void FunctionGraduate();
};
Graduate::Graduate(int sid, char* sname, int sage, int score,
int tid, char* tname, char* title,
int salary, char* addr)
:Student(sid,sname,sage, score),
Teacher(tid, tname, title),
_salary(salary){
int len = strlen(addr)+1;
this->_addr = new char[len];
strcpy(this->_addr, addr);
}
Graduate::~Graduate(){
delete[] this->_addr;
}
void Graduate::Display(){
cout << "SID = "<<this->_sid<<endl;
cout << "SName = "<<this->_sname<<endl;
cout << "SAge = "<<this->_sage<<endl;
//cout << "Score = "<<this->_score<<endl;
cout << "Salary = " << this->_salary << endl;
cout << "Address = " << this->_addr << endl;
}
void Graduate::ClassType(){
cout << "This is Graduate Class" << endl;
}
void Graduate::FunctionGraduate(){
cout << "Graduate::FunctionGraduate()" << endl;
}
int main(void){
Student stu(100, (char*)"s_river", 22, 60);
Teacher ter(999, (char*)"t_river", (char*)"Professor");
Graduate grt(100, (char*)"g_s_t_river", 22, 60, 999, (char*)"g_s_t_river", (char*)"Professor",10001,(char*)"Wuhan");
Student* pstu = &stu;
Teacher* pter = &ter;
Graduate* pgrt = &grt;
pstu->Display();
pstu->ClassType();
pstu->FunctionStudent();
pter->Display();
pter->ClassType();
pter->FunctionTeacher();
pgrt->Display();
pgrt->ClassType();
pgrt->FunctionGraduate();
cout << "sizeof(Student) = " << sizeof(stu) << " sizeof(Student*) = " << sizeof(pstu) << endl;
cout << "sizeof(Teacher) = " << sizeof(ter) << " sizeof(Teacher*) = " << sizeof(pter) << endl;
cout << "sizeof(Graduate) = " << sizeof(grt) << " sizeof(Graduate*) = "<<sizeof(pgrt) << endl;
cout << "Student* pstu = &grt "<< endl;
pstu = &grt;
pstu->Display();
pstu->ClassType();
pstu->FunctionStudent();
cout << "Teacher* pter = &grt " << endl;
pter = &grt;
pter->Display();
pter->ClassType();
pter->FunctionTeacher();
return 0;
}
分析:子类将每个父类的虚表指针_vptr都继承下来,并指向自身的虚表,虚表的每一项都是一个虚函数的入口地址。
虚表存放虚函数入口地址的顺序是按照虚函数声明的顺序进行存储。若派生类中重写了基类中某个虚函数,那么子
类在构造虚函数表时将该虚函数在基类虚函数表中所在的位置替换成子类本身的需函数。注意:派生类将自己特有
的虚函数入口地址存储在所继承的第一个基类的虚函数表的后面。
=====================================================End
========================================
由于知识存储有限, 以上内容若有错误或者不恰当的地方,欢迎广大网友留言指正。