50 - 55知识点

1、第50节

C++中的类对象在内存布局上与结构体相同
访问权限关键字在运行时失效

2、第51节

子类是由父类成员叠加子类新成员得到的

  • C++多态
    相同的行为方式:同一条调用语句
    不同的行为结果:同一条调用语句得到不同的执行结果
virtual void print()
{
	cout << "I'm Parent." << endl;
}

void print()			//由于继承没必要写virtual,也是虚函数
{
	cout << "I'm Child." << endl;
}

void how_to_print(Parent* p)
{
	p->print();				//展现多态的行为
}
  • C++多态的实现原理
    — 当类中声明虚函数时,编译器会在类中生成一个虚函数表
    — 虚函数表是一个存储成员函数地址的数据结构
    — 虚函数表是由编译器自动生成与维护的
    virtual 成员函数会被编译器放入虚函数表中
    — 存在虚函数时,每个对象中都有一个指向虚函数表的指针,这个指针一般放在最开头的位置、

分析:一般一个父类,一个子类。父类里面定义虚函数。当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个 存储成员函数地址 的地方,也就是函数指针,要知道虚函数的类型都是一样的,所以里面存放一个函数指针,却可以指向两个虚函数。
1、我们把虚函数表伪装成结构体,父类里面的第一个成员就是虚函数表类型的指针。
2、定义虚函数表指针的成员变量,指向一个虚函数表的对象(也就是用一个虚函数表伪装的结构体对象对它进行初始化)
3、真正的虚函数时另一种类型,我们看到的虚函数其实只是一个外部包装的,其实里面的实现都是一直用指针指向到另一种类型的虚函数。

3、第52节

  • 面向对象中的抽象类
    — 可用于表示现实世界中的抽象概念
    — 是一种只能定义类型,而不能产生对象的类
    — 只能被继承并重写相关函数
    — 直接特征是相关函数没有完整的实现

  • C++语言中没有抽象类的概念

  • C++通过纯虚函数实现抽象类

  • 纯虚函数是指只定义原型的成员函数

  • 一个C++类中纯在纯虚函数就成为了抽象类

纯虚函数的语法规则:

class Shape
{
public:
	virtual double area() = 0;
};

“= 0” 用于告诉编译器当前是声明纯虚函数,因此不需要定义函数体

  • 抽象类只能用作父类被继承
  • 子类必须实现虚函数的具体功能
  • 纯虚函数被实现后成为虚函数
  • 如果子类没有实现纯虚函数,则子类成为抽象类

— 满足下面的条件的C++类则成为接口
1、类中没有定义任何的成员变量
2、所有的成员函数都是公有的
3、所有的成员函数都是纯虚函数
4、接口是一种特殊的抽象类

4、第53节

  • 多重继承问题1
    通过多重继承得到的对象可能拥有“不同的地址”
    在这里插入图片描述
    在这里pa 和 pb 都是通过父类指针指向子类对象,指向相同的对象但是地址确实不一样的。

  • 多重继承问题2
    多重继承可能产生冗余的成员

解决方案:虚继承

class People{ };
class Teacher:virtual public People
{ 
};
class Student:virtual public People
{
};
class Doctor:public People,public Student
{

};
  • 虚继承能够解决数据冗余的问题
  • 中间层父类不再关心顶层父类的初始化
  • 最终子类必须直接调用顶层父类的构造函数

改成:

class Doctor:public Student,public Teacher
{
public:
	Doctor(string name, int age) :Teacher(name, age), Student(name, age)
	{
	}
};

多重继承容易带来问题
— 可能出现“同一个对象的地址不同”的情况
— 虚继承可以解决数据冗余的问题
— 虚继承使得架构设计可能出现问题

  • 多重继承问题3
    多重继承可能产生多个虚函数表。

需要进行强制类型转换时应该用 dynamic_cast
在这里插入图片描述

  • 工程中常用单继承加多接口、

5、第54节
关于虚函数

  • 构造函数不可能成为虚函数
    构造函数执行结束之后,虚函数表指针才会被正确的初始化
  • 析构函数可以成为虚函数
    建议在设计类的时候将析构函数声明为虚函数
  • 构造函数中不可能发生多态行为
    在构造函数执行时,虚函数表指针未被正确初始化
  • 析构函数中不可能发生多态行为
    在析构函数执行时,虚函数表指针已经被销毁

*** 关于继承中的强制类型转换
条件:
1、dynamic_cast 是与继承相关的类型转换关键字
2、dynamic_cast 要求相关的类中必须有虚函数

  • 用于直接或间接继承关系的指针(引用)之间
    — 指针:
       转换成功:得到目标类型的指针
       转换失败:得到一个空指针
    — 引用:
       转换成功:得到目标类型的引用
       转换失败:得到一个异常操作信息
#include <iostream>
using namespace std;

class Base
{
public:
	Base()
	{

	}
	virtual ~Base()
	{

	}
};

class Derived : public Base
{
public:
	Derived()
	{

	}
	~Derived()
	{

	}
};

int main()
{
	Base* p = new Derived;

	Derived* pd = dynamic_cast<Derived*>(p);

	cout << "pd = " << pd << endl;

	return 0;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值