C++学习笔记(十四)多态原理与虚函数

本文深入探讨了C++中虚函数的工作原理,包括构造和析构的顺序、虚函数表的使用,以及如何通过虚函数实现多态。此外,还讨论了如何计算类的大小,并解释了虚函数在构造函数中无法实现多态的原因。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

构造的顺序:沿着类的继承路径网上最顶层的父类,从最顶层的父类依次往下开始构造

析构的顺序:从当前类开始沿着类的继承路径网上查找父类,依次析构,直到最顶层父类为止

#include <iostream>
using namespace std;
class Animal
{
public:
virtual void eat()
{
cout << "动物吃饭" << endl;
}
void sleep()
{
cout << "动物睡觉" << endl;
}
private:
int a;

};

class Cat : public Animal
{
public:
virtual void eat()
{
cout << "猫吃鱼" << endl;
}
void sleep()
{
cout << "猫睡觉" << endl;
}
private:
int b;
};
void func(Animal *pa)
{
// 如何确定传过来的对象类型?
// ====>  如何找到 传过来的对象的相应函数?
// 通过虚函数  ========>  虚函数干了什么?
// 1、通过基类指针 找到   虚函数指针
// 2、通过虚函数指针找到  虚函数表
// 3、在虚函数表中找到    需要执行的函数

pa->eat();   // pa->vfptr->eat()
pa->sleep();
}
int main()
{
cout << sizeof(Animal) << endl;   //8
      cout << sizeof(Cat) << endl;        //12

Animal a;
Cat    c, c1, c2, c3;
func(&a);  
func(&c);     //猫吃鱼而不是动物吃饭
getchar();
return 0;
}

使用sizeof()计算类大小的一些基本原则

       (1)类的大小为类的非静态成员数据的类型大小之和,也就是说静态成员数据不作考虑;

       (2)类的总大小也遵守类似class字节对齐的,调整规则;(参考5分钟搞定内存字节对齐)

       (3)成员函数都是不会被计算的;

       (4)如果是子类,那么父类中的成员也会被计算;

       (5)虚函数由于要维护虚函数表,所以要占据一个指针大小,也就是4字节。

总结即:一个类中,虚函数、成员函数(包括静态与非静态)和静态数据成员都不占用类对象的存储空间。

因为一个空类也要实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof()为1。

C++虚函数机制

C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。

具体详细原理:https://blog.youkuaiyun.com/haoel/article/details/1948051/


// ====> 构造函数中是无法实现多态的,原因:
// 虚函数指针在初始化的时候,是分步进行初始化的,执行到哪一个类的构造函数,该指针就指向这个类的虚函数表
// 对于 Cat
// 1、先调用Animal的构造函数,则 vfptr 指向Animal的虚函数表
// 2、调用 Cat 的构造函数, 则 vfptr 指向Cat的虚函数表

#include <iostream>
using namespace std;
class Animal
{
public:
Animal()
{
cout << "动物的构造函数" << endl;
eat();
cout << "-------------------" << endl;
}
virtual void eat()
{
cout << "动物吃饭" << endl;
}
private:
int a;
};

class Cat : public Animal
{
public:
Cat()
{
cout << "猫的构造函数" << endl;
eat();
cout << "-------------------" << endl;
}
virtual void eat()
{
cout << "猫吃鱼" << endl;
}
void sleep()
{
cout << "猫睡觉" << endl;
}
private:
int b;
};
int main()
{
Cat c;
getchar();
return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值