C++ ------>多态__02
  L8iEHH07GzZb 2023年11月22日 50 0

各位好友, 本期继续推进  继承下, 多态 !

------>Override ~~ Final (C++11)

(a). Final :修饰虚函数表示该虚函数不能被 /重写

(b). Override : 检查派生类是否构成 /重写基类的 /某一个虚函数如果没有重写 /编译会报错

------->实现环节 :>

//----->C++ 11
//----->演示__Final
#include <iostream>

using std :: cout;
using std :: endl;

class Fruits 
{
public:
  virtual void Price() final {cout << "全场水果__每镑 7 美金" << endl;}
};

class apple : public Fruits
{
public:
	virtual void Price() {cout << "What!难不成苹果成了 金苹果 !" << endl;}
};

int main()
{
  
	return 0;
}

------->NO a .

C++ ------>多态__02_函数指针数组打印地址


------->NO b .

C++ ------>多态__02_探究__虚表_02


------>设计出不想被继承的类, 如何设计 ?

------>方法 一 :基类构造函数私有化 (C++98) ---->方法 二 : 基类加一个 “final” (C++11)

------>重载 / 重写 / 重定义  --->三者比较 :>

C++ ------>多态__02_函数指针数组打印地址_03


------>接口继承 ~~ 实现继承

------>普通函数的继承是一种实现继承 派生类继承 /基类函数(可以使用的函数)继承 /函数实现

而虚函数 /继承是一种接口继承派生类 /继承的 /是基类虚函数的接口 重写之后 进而实现多态 

一般而言如果不实现多态避免将函数定义成 /虚函数  


各位好友, 下面__开战 多态原理先从 一道经典题入手 !

----->如下 :>

//一道常见面试题
//
class Base
{
public:
  virtual void Func1() 
  {
  	cout << "Func1()" <<endl;
  }
private:
  char _b = 1;
};

//计算 Base 类大小
int main()
{
  cout << sizeof(Base) << endl;
	return 0;
}



为了好友们, 有更好的观感体验, 现附上 彩色 代码图样 :>

C++ ------>多态__02_重载/重写/重定义__三者比较_04



--------->运行调试 :>

C++ ------>多态__02_探究__虚表_05



--------->内存调用 :>

C++ ------>多态__02_多态底层原理_06



--------->符合多态 :

--------->底层汇编 :>

C++ ------>多态__02_函数指针数组打印地址_07


--------->符合多态 :

--------->底层汇编 :>

C++ ------>多态__02_函数指针数组打印地址_08



--------->探究 引用 指针切片 / 差异性 :>

//对象引用 与指针切片 ----->差异
//
#incluide <iostream>

using std ::cout;
using std :: endl;

class Person
{
public:
  virtual void _BuyTicket() const {cout << "全价_火车票" << endl;}
  
protected:
  int _a = 0;
};

class Student : public Person
{
public:
	virtual void _BuyTicket() const {cout << "半价_火车票" << endl;}
protected:
	int _b = 1;
};

void _BuyTicket(const Person& p)
{
	p._BuyTicket();
}

int main()
{
  Person pp;
  
  Student stu;
	return 0;
}



--------->引用切片 :>

C++ ------>多态__02_多态底层原理_09



--------->指针切片 :>

C++ ------>多态__02_指针___引用__切片行为_10



多态是如何用 /虚函数表指针 /指向 /派生类去调用派生类对象, 指向 /基类会去调用基类对象

· 指针 /指向基类去调用 基类对象地址 指向派生类去调用 派生类对象地址

· 派生类会将基类虚表 /拷贝下来之后有一个 /虚函数覆盖(重写)/形成 /派生类虚表

------>注意 :>

· 多态情况下指针 或者 引用 是不存在 拷贝 切片的

· 指针 /指向基类 /会去调用/基类对象指向派生类 /会去调用 /派生类里面 /基类 /那一部分

· 最终编译器进行调用看到的”  仍然是 /基类那一部分的切片 ; 但是 /由于发生了切片

· P 指针 /指向虚表内 /原先的地址 /就会被覆盖 /重写 ,指针 P 指向基类 /会在 基类虚表内 /寻找 /基类地址 .


------->NO1.

C++ ------>多态__02_函数指针数组打印地址_11



------->NO2.

C++ ------>多态__02_探究__虚表_12


/回顾一下多态 /条件 :>

(1).  虚函数必须进行重写 (2).  参数调用必须要 /基类的指针 引用

 然而,参数部分,为什么不能是 /派生类指针 或者 引用 为什么 /不能是 /基类对象

-------->答案 :>

·  派生类赋值给基类对象 /要切片 不会拷贝虚表

· 如果 /基类对象可以赋值给派生类必须要拷贝虚表 ;  基类虚表中是派生类 /还是基类就不确定了

·  /虚表拷贝之后 会出现__基类虚表指针 /调用对象 /不再明确调用过程 /基类 /竟可以调用派生类


-------->虚表存储位置 :

------->代码如下 :>

//探究虚表在哪里 ?
//
class Person
{
public:
  virtual void _BuyTicket()
  {
    cout << "全价火车票" <<endl;
  }
};

class Student : public Person
{
public:
	virtual void  _BuyTicket()
  {
  	cout << "半价火车票" << endl;
  }
};

void _BuyTicket(const Person& p)
{
	p._BuyTicket();
}

int main()
{
  Person pp;
  
  Student stu;
  
  int a = 0;
  printf("栈区 :%p\n", &a);
  
  static int b = 1;
  printf("静态区 :%p\n", &b);
  
  int* ptr = new int;
  printf("‘堆区 : %p\n’, &ptr");
  
  const char* pstr = "Hello world !";
  printf("常量区 :%p\n", &pstr);
  
  printf("虚表1 :> %p\n", *((int*)&pp));
  
  printf("虚表2 :> %p\n", *((int*)&stu));
	return 0;
}



为了方便好友们, 有更好的观感体验, 现附上 彩色 代码图样 :>

C++ ------>多态__02_重载/重写/重定义__三者比较_13


--------->虚函数重写 :本质上重写__虚函数的实现

--------->普通函数 /继承, 实际上,是 /实现继承 而对于 /多态继承, 实际上, 是 /接口继承

---------->调试 及监视内存窗口 :>

C++ ------>多态__02_多态底层原理_14



---------->验证 :>

//运用函数指针数组的方式
//寻找出 监视窗口隐藏的 Func3()函数
//对象引用 与指针切片 -----》区别 ~~差异
//
#incluide <iostream>

using std ::cout;
using std :: endl;

class Person
{
public:
  virtual void _BuyTicket() const {cout << "全价_火车票" << endl;}
  
protected:
  int _a = 0;
};

class Student : public Person
{
public:
	virtual void _BuyTicket() const {cout << "半价_火车票" << endl;}
protected:
	int _b = 1;
};

void _BuyTicket(const Person& p)
{
	p._BuyTicket();
}

//函数指针数组
typedef void(*FUNC_PTR) ();

void Print_PTR(FUNC_PTR* table)
{
	for(size_t i = 0; table[i] != nullptr; i++)
  {
  	printf("[%d] : %p\n", i, table[i]);
  }
  
  cout << endl;
}

int main()
{
  Person pp;
  int VFT1	= *((int*)&pp);
  Print_PTR(VFT1);
  
  Student stu;
  int VFT2 = *((int*)&stu);
  Print_PTR(VFT2);
	return 0;
}



--------->寻找 Func3() 函数 : >

C++ ------>多态__02_探究__虚表_15


------->小结 :>

------>派生类虚表生成

A . 先将基类中 /虚表内容拷贝一份到派生类 /虚表里面

B . 派生类增加 /虚函数,按照 /类中声明的顺序 依次增加 /派生类虚表 ;

C . 如果, 派生类重写 /基类中 /某一个虚函数 那么派生类虚表 /会去覆盖/基类的虚表


各位好友, 本期内容, 已完结 !

下一期, 开战 / 新领域  --->二叉搜素树(进阶版)  敬请期待 !😊😊


【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月22日 0

暂无评论

L8iEHH07GzZb