软件需求请点击此处留言菜鸟资源为你准备 立即查看

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

在C++中,当我们想要在派生类中重载赋值运算符时,我们需要遵循一些特定的规则和约定。这是因为赋值运算符在派生类中涉及到基类的成员,并且涉及到对象自身的状态。 接第 第十二章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人...

当前版本

软件大小

软件语言

是否破解

在C++中,当我们想要在派生类中重载赋值运算符时,我们需要遵循一些特定的规则和约定。这是因为赋值运算符在派生类中涉及到基类的成员,并且涉及到对象自身的状态。

接第 第十二章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人 – 菜鸟资源 (xiciw.com) 继续讲解

以下是一个简单的示例,演示如何在派生类中重载赋值运算符:

  1. #include <iostream>
  2. class Base {
  3. public:
  4. int x;
  5. Base(int value) : x(value) {}
  6. };
  7. class Derived : public Base {
  8. public:
  9. Derived(int value) : Base(value) {}
  10. // 派生类的赋值运算符重载
  11. Derived& operator=(const Derived& other) {
  12. if (this != &other) { // 避免自赋值
  13. Base::operator=(other); // 调用基类的赋值运算符
  14. // 这里可以添加派生类的其他成员的赋值逻辑
  15. }
  16. return *this; // 返回对调用对象的引用,以便链式赋值
  17. }
  18. };
  19. int main() {
  20. Derived d1(10);
  21. Derived d2(20);
  22. d1 = d2; // 使用派生类的赋值运算符重载
  23. std::cout << d1.x << std::endl; // 输出:20
  24. return 0;
  25. }

在上述代码中,我们首先定义了一个基类Base和一个派生类Derived。在Derived类中,我们重载了赋值运算符。这个重载的赋值运算符首先检查是否是自赋值(即this指针是否等于other的地址),然后调用基类的赋值运算符,最后添加派生类的其他成员的赋值逻辑。

注意,为了保持一致性和正确性,我们通常在派生类的赋值运算符重载中显式地调用基类的赋值运算符。

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.6. 派生类的赋值运算符重载

赋值运算符函数不是构造器,所以可以继承,语法上就没有构造器的严格一些。

7.6.1. 格式

  1. 子类& 子类::operator=(const 子类& another)
  2. {
  3. if(this == &another)
  4. return *this; //防止自赋值
  5. 父类::operator =(another); // 调用父类的赋值运算符重载
  6. this->salary = another.salary;//子类成员初始化
  7. return * this;
  8. }

7.6.2. 代码
 基类
student.h

  1. Student & operator=(const Student & another);

student.cpp

  1. Student & Student::operator=(const Student & another)
  2. {
  3. this->name = another.name;
  4. this->num = another.num;
  5. this->sex = another.sex;
  6. return * this;
  7. }

 派生类

graduate.h

  1. Graduate & operator=(const Graduate & another);

graduate.cpp

  1. Graduate & Graduate::operator=(const Graduate & another)
  2. {
  3. if(this == &another)
  4. return *this;
  5. Student::operator =(another);
  6. this->salary = another.salary;
  7. return * this;
  8. }

 测试代码

  1. int main()
  2. {
  3. Graduate g("liuneng",2001,'x',2000);
  4. g.dump();
  5. Graduate gg = g;
  6. gg.dump();
  7. cout<<"-----------"<<endl;
  8. Graduate ggg("gege",2001,'x',4000);
  9. ggg.dump();
  10. ggg = g;
  11. ggg.dump();
  12. return 0;
  13. }

7.6.3. 结论:

派生类的默认赋值运算符重载函数,会调用父类的默认或自实现函数。派生类若自实现,

则不会发生调用行为,也不报错。需要自实现。

7.7. 派生类析构函数的语法

派生类的析构函数的功能是在该对象消亡之前进行一些必要的清理工作,析构函数没有类

型,也没有参数。析构函数的执行顺序与构造函数相反。

析构顺序

  1. 子类->成员->基类

无需指明析构关系。why? 析构函数只有一种,无重载,无默参。

7.8. 派生类成员的标识和访问

7.8.1. 作用域分辨符

 格式:

  1. 基类名::成员名;基类名::成员名(参数表);

如果某派生类的多个基类拥有同名的成员,同时,派生类又新增这样的同名成员,在

这种情况下,派生类成员将 shadow(隐藏)所有基类的同名成员。这就需要这样的调用方式

才能调用基类的同名成员。

 代码

  1. #include <iostream>
  2. using namespace std;
  3. class Base
  4. {
  5. public:
  6. void func(int)
  7. {
  8. cout<<"haha"<<endl;
  9. }
  10. };
  11. class Drive:public Base
  12. {
  13. public:
  14. void func()
  15. {
  16. // func(); //func 死循环
  17. // Base::func(); //被 shadow 的成员,可以这样访问
  18. cout<<"hehe"<<endl;
  19. }
  20. };
  21. //
  22. int main()
  23. {
  24. Drive d;
  25. d.func(); // 访问派生类成员
  26. // d.Base::func(3); //访问基类成员
  27. return 0;
  28. }

 小结

重载:同一作用域 ,函数同名不同参(个数,类型,顺序);

隐藏:父子类中,标识符(函数,变量)相同,无关乎返值和参数(函数),或声明类

(变量)

7.8.2. 继承方式

7.8.2.1. 图示

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.8.2.2. 详解

 public 公有继承

当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。

 private 私有继承

当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。

 protected 保护继承

保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。

图示之:

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.8.3. 派生类成员属性划分为四种:

公有成员;保护成员;私有成员;不可访问的成员;

  1. #include <iostream>
  2. using namespace std;
  3. class Base
  4. {
  5. public:
  6. int pub;
  7. protected:
  8. int pro;
  9. private:
  10. int pri;
  11. };
  12. class Drive:public Base
  13. {
  14. public:
  15. void func()
  16. {
  17. pub = 10;
  18. pro = 100;
  19. // pri = 1000;
  20. }
  21. };
  22. //
  23. int main()
  24. {
  25. Base b;
  26. b.pub = 10;
  27. // b.pro = 100;
  28. // b.pri = 1000;
  29. return 0;
  30. }

7.9. why public

7.9.1. 继承方式与成员访问属性

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.9.2. 公有继承的意义:

  1. #include <iostream>
  2. using namespace std;
  3. class Base
  4. {
  5. public:
  6. int pub;
  7. protected:
  8. int pro;
  9. private:
  10. int pri;
  11. };
  12. class Drive:public Base
  13. {
  14. public:
  15. };

private 在子类中不可见,但仍可通过父类接口访问。

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.9.2. 公有继承的意义:

  1. #include <iostream>
  2. using namespace std;
  3. class Base
  4. {
  5. public:
  6. int pub;
  7. protected:
  8. int pro;
  9. private:
  10. int pri;
  11. };
  12. class Drive:public Base
  13. {
  14. public:
  15. };

private 在子类中不可见,但仍可通过父类接口访问。

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

public 作用:传承接口 间接的传承了数据(protected)。

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

protected 作用:传承数据,间接封杀了对外接口。

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

private 统杀了数据和接口

1.只要是私有成员到派生类中,均不可访问. 正是体现的数据隐蔽性.其私有成员仅可被本类的成员函数访问

2.如果多级派生当中,均采用 public,直到最后一级,派生类中均可访问基类的public,protected 成员.

兼顾了数据的隐蔽性和接口传承和数据传递

3.如果多级派生当中,均采用 private,直到最后一级,派生类中基类的所有成员均变为不可见.

只兼顾了数据的隐蔽性

4.如果多级派生当中,均采用 protected,直到最后一级,派生类的基类的所有成员即使可见,也均不可被类外调用

只兼顾了数据的隐蔽性和数据传递

综上所述:记住 public 足矣。

7.9.3. 私有继承和保护继承的存在意义

此两种方式有效的防止了基类公有接口的扩散。是一种实现继承,而不是一种单纯的isA 的关系了。

  1. class Windows
  2. {
  3. public:
  4. 一般常见基础接口
  5. protected:
  6. 常用特效接口
  7. 高级特效接口
  8. private:
  9. duang 特效接口
  10. };

7.10.多继承

从继承类别上分,继承可分为单继承和多继承,前面讲的都是单继承。

7.10.1. 多继承的意义

俗话讲的,鱼与熊掌不可兼得,而在计算机就可以实现,生成一种新的对象,叫熊掌

鱼,多继承自鱼和熊掌即可。还比如生活中,“兼”。

7.10.2. 继承语法

  1. 派生类名::派生类名(参数总表)
  2. :基类名 1(参数表 1),基类名(参数名 2)....基类名 n(参数名 n),
  3. 内嵌子对象 1(参数表 1),内嵌子对象 2(参数表 2)....内嵌子对象 n(参数表 n
  4. {
  5. 派生类新增成员的初始化语句;
  6. }

7.10.3. 沙发床实现

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.10.3.1. 继承结构:

7.10.3.2. 代码:

 床类

bed.h

  1. #ifndef BED_H
  2. #define BED_H
  3. class Bed
  4. {
  5. public:
  6. Bed();
  7. ~Bed();
  8. void sleep();
  9. };
  10. #endif // BED_H

bed.cpp

  1. #include "bed.h"
  2. #include "iostream"
  3. using namespace std;
  4. Bed::Bed()
  5. {
  6. }
  7. Bed::~Bed()
  8. {
  9. }
  10. void Bed::sleep()
  11. {
  12. cout<<"take a good sleep"<<endl;
  13. }

 沙发类

sofa.h

  1. #ifndef SOFA_H
  2. #define SOFA_H
  3. class Sofa
  4. {
  5. public:
  6. Sofa();
  7. ~Sofa();
  8. void sit();
  9. };
  10. #endif // SOFA_H

sofa.cpp

  1. #include "sofa.h"
  2. #include "iostream"
  3. using namespace std;
  4. Sofa::Sofa()
  5. {
  6. }
  7. Sofa::~Sofa()
  8. {
  9. }
  10. void Sofa::sit()
  11. {
  12. cout<<"take a rest"<<endl;
  13. }

 沙发床类

sofabed.h

  1. #ifndef SOFABED_H
  2. #define SOFABED_H
  3. #include "sofa.h"
  4. #include "bed.h"
  5. class SofaBed:public Sofa,public Bed
  6. {
  7. public:
  8. SofaBed();
  9. ~SofaBed();
  10. };
  11. #endif // SOFABED_H

sofabed.cpp

  1. #include "sofabed.h"
  2. SofaBed::SofaBed()
  3. {
  4. }
  5. SofaBed::~SofaBed()
  6. {
  7. }

 测试代码:

main.cpp

  1. #include <iostream>
  2. #include "sofa.h"
  3. #include "bed.h"
  4. #include "sofabed.h"
  5. using namespace std;
  6. int main()
  7. {
  8. Sofa s;
  9. s.sit();
  10. Bed b;
  11. b.sleep();
  12. SofaBed sb;
  13. sb.sit();
  14. sb.sleep();
  15. return 0;
  16. }

7.10.4. 三角问题(二义性问题)

  1. #include <iostream>
  2. using namespace std;
  3. class X
  4. {
  5. public:
  6. X(int d)
  7. :_data(d){}
  8. void setData(int i)
  9. {
  10. _data = i;
  11. }
  12. int _data;
  13. };
  14. class Y
  15. {
  16. public:
  17. Y(int d)
  18. :_data(d){}
  19. int getData()
  20. {
  21. return _data;
  22. }
  23. int _data;
  24. };
  25. class Z:public X,public Y
  26. {
  27. public:
  28. Z():X(2),Y(3)
  29. {}
  30. void dis()
  31. {
  32. cout<<X::_data<<endl;
  33. cout<<Y::_data<<endl;
  34. }
  35. };
  36. int main()
  37. {
  38. Z z;
  39. z.dis();
  40. z.setData(2000);
  41. cout<<z.getData()<<endl;
  42. return 0;
  43. }

7.10.5. 钻石问题

第十三章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

7.10.5.1. 三角转四角

采用提取公因式的方法

  1. #include <iostream>
  2. using namespace std;
  3. class M
  4. {
  5. public:
  6. M(int i)
  7. :_data(i){}
  8. int _data;
  9. };
  10. class X:public M
  11. {
  12. public:
  13. X(int d)
  14. :M(d){}
  15. void setData(int i)
  16. {
  17. _data = i;
  18. }
  19. };
  20. class Y:public M
  21. {
  22. public:
  23. Y(int d)
  24. :M(d){}
  25. int getData()
  26. {
  27. return _data;
  28. }
  29. };
  30. class Z:public X,public Y
  31. {
  32. public:
  33. Z():X(2),Y(3)
  34. {}
  35. void dis()
  36. {
  37. cout<<X::_data<<endl;
  38. cout<<Y::_data<<endl;
  39. }
  40. };
  41. int main()
  42. {
  43. Z z;
  44. z.dis();
  45. z.setData(2000);
  46. cout<<z.getData()<<endl;
  47. return 0;
  48. }

7.10.5.2. 虚继承

  1. #include <iostream>
  2. using namespace std;
  3. class M
  4. {
  5. public:
  6. M(int d)
  7. :_data(d)
  8. {}
  9. int _data;
  10. };
  11. class X :virtual public M
  12. {
  13. public:
  14. X(int d)
  15. :M(d){}
  16. void setD(float d)
  17. {
  18. _data = d;
  19. }
  20. };
  21. class Y:virtual public M
  22. {
  23. public:
  24. Y(int d)
  25. :M(d){}
  26. int getD()
  27. {
  28. return _data;
  29. }
  30. };
  31. class Z:public X,public Y
  32. {
  33. public:
  34. Z(int _x,int _y):X(_x),Y(_y),M(100)
  35. {}
  36. void dis()
  37. {
  38. // cout<<X::_data<<endl;
  39. // cout<<Y::_data<<endl;
  40. cout<<_data<<endl;
  41. }
  42. };
  43. int main()
  44. {
  45. Z z;
  46. z.dis();
  47. z.setData(2000);
  48. cout<<z.getData()<<endl;
  49. return 0;
  50. }

7.10.5.3. 小结
 虚继承的意义
在多继承中,保存共同基类的多份同名成员,虽然有时是必要的,可以在不同的
数据成员中分别存放不同的数据,但在大多数情况下,是我们不希望出现的。因为保
留多份数据成员的拷贝,不仅占有较多的存储空间,还增加了访问的困难。
为此,c++提供了,虚基类和虚继承机制,实现了在多继承中只保留一份共同成员。 虚基类,需要设计和抽象。
虚继承,是一种继承的扩展。
 语法总结
a. M 类称为虚基类(virtual base class ),是抽象和设计的结果。
b. 虚继承语法

  1. class 派生类名:virtual 继承方式 基类名

c.虚基类及间接类的实始化

  1. class A{
  2. A(int i)
  3. {}
  4. };
  5. {
  6. B(int n):A(n){}
  7. };
  8. class C:virtual public A
  9. {
  10. C(int n):A(n){}
  11. };
  12. class D:public B,public C
  13. {
  14. D(int n)
  15. :A(n),B(n),C(n)
  16. {}
  17. };

7.10.5.4. 改造沙发床

这一章就到这里!下一章我们讲解多态(PolyMorphism)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

常见问题

  • 如何安装和激活?

    每款软件会附带有安装教程,您打开安装包一目了然

  • 程序是否已损坏?文件损坏?还是其他错误?

    有错误问题,请您参考:https://www.xxx.com/error

  • 如何更新?正式激活后会发生什么情况?

    除非安装说明中另有说明,否则官方更新可能会导致无法激活。 要从本网站更新软件,您需要在此处下载此软件的新版本(如果可用),并将其安装在计算机上安装的版本之上(替换)。在这种情况下,您将保存此软件的激活和设置。

  • 如何下载?链接不起作用?

    我们使用百度网盘,132云盘和微软网盘,除了百度网盘,其他两款不限速,如果链接失效,请您联系客服处理

  • 已发布更新。我什么时候升级我的版本?

    所有软件如有更新,我们第一时间推送,视自己情况更新使用

  • 如何更改语言?

    打开“系统偏好设置”->“通用>语言和地区”->应用程序-“+”。 选择应用和语言。此方法适用于大多数应用程序。 Adobe 产品中的语言通常是在产品本身的安装阶段选择的。 游戏中的语言通常会在游戏本身的设置中发生变化。

  • 如何删除软件?

    有很多选择。最简单的方法是使用特殊的实用程序来卸载应用程序,例如App Cleaner Uninstaller 要删除 Adobe 产品,请使用 Creative Cloud Cleaner Tool

  • 需要远程帮助吗?

    网站已开通永久会员的可享受免费远程,如果非永久会员,远程安装另外收费

技术教程

第十二章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-2-1 9:49:57

技术教程

第十四章丨C++编程宝典:快速上手、深入进阶、挑战高级技巧,助你成为编程达人

2024-2-3 9:32:22

0 条回复 A文章作者 M管理员
欢迎您,新朋友,感谢参与互动!
    暂无讨论,说说你的看法吧
后退
榜单