C++复习之路25:父类与子类指针转换,sizeof相关:

构造、析构函数、虚函数相关,参看这里

1.当自己的类指针指向自己类的对象时,无论调用的是虚函数还是实函数,其调用的都是自己的(那必须的啊)

2.当指向父类对象的父类指针被强制转换成子类指针时候,子类指针调用函数时,只有非重写函数是自己的,虚函数是父类的;

3.当指向子类对象的子类指针被强制转换成父类指针的时候,也就是父类指针指向子类对象,此时,父类指针调用的虚函数都是子类的,而非虚函数都是自己的;

 class A1
 {public:
	 int a = 0;	 
	 virtual int fu()
	 {
		 return 0;
	 };
	 virtual int fu2() {
		 return 0;
	 };
 };
 class B1 :A1
 {
 public:
	 int num = 2;
	 int fu()
	 {
		 return num;
	 }
 };
int main()
{
	A1 *aa = new A1();
	int sizea = sizeof(A1);
	B1 *b=new B1();
	A1 *a = (A1*)b;
    return 0;
}

如图为子类B1的类内布局,及其虚函数表

可以看出,对于子类B1,其中重写过的fu才是B1的,fu2没重写过,所以如果调用的话,只会调用父类的fu2函数。

需要注意的是一个类不管有多少个虚函数,虚函数指针(可以理解为虚函数表的表头指针)对于类的一个对象来说只有一个,所以sizeof(A1),32位下是8(4+4,4字节对齐),  64位下为16,(4+8,还要再算上8字节对齐,所以是16)

sizeof(B1),32位下为sizeof(A1)  8+4=12

sizeof()是运算符,由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小。实际上,用sizeof来返回类型以及静态分配的对象、结构或数组的空间,返回值跟这些里面所存储的内容没有关系。 对于类来说,sizeof只会考虑到变量和虚函数,以及基类,不考虑成员函数和静态变量。对子类sizeof的操作,先计算基类再+上子类独有的

此处涉及虚函数表的原理,或者说是类内布局:

需要主要的是子类转换为父类,会被屏蔽(内存布局是先父类的虚函数表指针、父类成员变量,然后才是子类的成员变量,如果父类没有虚函数,子类有的话,这里还要考虑子类的虚函数表指针,所以理论上很好屏蔽)掉子类独有的成员函数和成员变量,父类指针,只能操作子类的虚函数和父类拥有的变量和父类的成员函数。

4.虚函数与函数重载,多态

什么是多态:同一个实体,同时具有多种形式

向不同的对象发送同一条消息(即函数调用)

不同的对象在接收时会产生不同的行为(即不同的函数实现)

多态的两种方式:

1.函数重载的方式(静态多态或编译时多态)

2.函数重写的方式(动态多态或运行时多态)
2.1 要实现C++函数重写,必须要先把父类的成员函数设定为虚函数

注意1

 

派生类重写基类方法时可以加上override关键字表示重写

override关键字为C++11标准后新加入的,用来明确派生类重写基类继承过来的虚函数

 

注意2

为了能够让同一个函数操作不同类型的子类对象,所以我们把参数类型定义成了基类对象

当传递子类类型时,参数类型可以自动转化(子类对象可以赋值给父类对象)

子类转换为父类:向上转型,使用dynamic_cast<type_id>(expression),这种转换相对来说比较安全不会有数据的丢失;

 

父类转换为子类:向下转型,可以使用强制转换,这种转换时不安全的,会导致数据的丢失,原因是父类的指针或者引用的内存中可能不包含子类的成员的内存。

如图,父类指针aa转换成子类,但是父类中没有子类独有的一些函数,这造成编译通过,但是运行会出错。

虚函数也是类的成员函数 

 

虚函数和函数重载都实现了C++的多态性,但表现形式不一样,函数重载调用根据参数个数、参数类型等进行区分,而虚函数则是根据动态联编来确定调用什么,

函数重载可以是类的成员函数也可以是非成员函数,比如:

1

2

int fun(int a);

int fun(int a, int b);

这就是非成员重载,虚函数必须是成员函数了,否则就失效了

函数重载的定义:

        两个以上的函数,具有相同的函数名,但是形参的个数或者类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数,这就是函数的重载。

重载函数的四个注意,前两个可以混合使用:

个数不同:  int add(int x, int y);     int add(int x, int y, int z);

类型不同:int add(int x, int y);  int add(float x, float y);  

不以形参名来区分函数

不以返回值来区分函数

猜你喜欢

转载自blog.csdn.net/weixin_42067304/article/details/108547910