什么是虚函数?
用virtual 修饰的成员函数叫虚函数
-
没有虚构造函数
-
不写虚函数,没有默认的虚函数
-
虚函数对于类的影响:增加一个指针的内存
-
虚函数的存储:虚函数表(了解内容:就是一个指针存储所有虚函数的首地址[函数指针],只有指针[4字节]可以操作一段内存)
-
用来实现多态以及ADT(抽象数据类型)过程
普通函数不影响类的内存
class MM
{
public:void print() {cout << "普通函数"<< endl;//普通函数不影响类的内存--->普通函数存在另一段内存中}
protected:};void testVirtual()
{//C语言不允许存在空的结构体,c++允许存在cout << sizeof(MM) << endl;/*(没有数据成员的)空的类或者结构体占用1字节 用1字节标识当前内存为结构体内存*/
}
int main()
{testVirtual();return 0;
}
/*输出*/1
虚函数会影响类的内存
增加一个指针的内存,32位操作系统多4个字节 ,64位操作系统多8个字节
class MM
{
public:virtual void print1() {cout << "虚函数1"<< endl;}/*virtual void print2(){cout << "虚函数2" << endl;} 无论多少个虚函数,所增加的字节都是一个指针的字节--->多了一个虚函数,还是4个字节所有的虚函数其实是用一个函数指针去存储的:把这个函数指针所指向的这一段内存称为虚函数表*/
protected:
};
void testVirtual()
{cout << sizeof(MM) << endl;
}
int main()
{testVirtual();return 0;
}
/*输出*/4
小知识:空的类|结构体占1个字节,一旦有了数据,标识位就不存在了
class A
{int num; //输出4而不是输出5 (4+1)
};
class B
{//用1字节标识当前内存为结构体内存
};
void testVirtual()
{cout << sizeof(A) << endl;cout << sizeof(B) << endl;
}
int main()
{testVirtual();return 0;
}/*输出*/4
1
了解虚函数表--->通过虚函数表的指针去访问数据|成员|函数
-
所有的虚函数其实是用一个函数指针去存储的,把这个函数指针指向的这一段内存称为虚函数表 就是一个指针存储所有虚函数的首地址(虚函数函数名)<--->函数指针
-
只有指针可以操作一段内存(4字节)
-
一个类的对象,对象的内存,如果没有数据,第一个内存存的是虚函数表的指针(类似二维数组)
-
没有数据,取对象的地址(二级指针),就是虚函数指针的地址,通过这种方式来访问
/*无论多少个虚函数,增加的字节就是一个指针的字节*/
通过虚函数表的理解去调用虚函数
class MM
{
public:virtual void print1() {cout << "虚函数1"<< endl;} virtual void print2() {cout << "虚函数2"<< endl;}
protected:
};
void testVirtual()
{
//虚函数表 MM mm; //构建一个对象int** vptr = (int** )&mm; //定义一个二级指针取对象的地址 强转类型typedef void(*PF)(); //函数指针类型定义别名PF func = (PF)vptr[0][0]; //强转类型把地址转为函数指针,访问第一个函数指针的地址func(); //通过虚函数表的函数指针调用第一个虚函数func = (PF)vptr[0][1];func(); //调用第二个虚函数
}
int main()
{testVirtual();return 0;
}
/*输出*/虚函数1
虚函数2
虚函数可以在类中声明,在类外实现,类外不需要virtual修饰,只需要类名限定就可以了
class MM
{
public:virtual void print3();protected:
};
void MM::print3()
{cout << "虚函数3" << endl;
}
int main()
{MM mm;mm.print3();return 0;
}
/*输出*/虚函数3