当前位置: 首页 > news >正文

广州天河 网站建设乌市网站建设为

广州天河 网站建设,乌市网站建设为,wordpress修改首页调用,小微企业注册流程及费用一、继承概念 在cpp中,封装、继承、多态是面向对象的三大特性。这里的继承就是允许已经存在的类(也就是基类)的基础上创建新类(派生类或者子类),从而实现代码的复用。 如上图所示,Person是基类&…

一、继承概念

在cpp中,封装、继承、多态是面向对象的三大特性。这里的继承就是允许已经存在的类(也就是基类)的基础上创建新类(派生类或者子类),从而实现代码的复用。

如上图所示,Person是基类,Stu与Tea是派生类,Stu与Tea分别继承了基类中的对象,同时也有自己的类对象。


1.1派生类对基类的修改

派生类对象可以赋值给基类对象、基类指针、基类引用,这里的赋值只是把派生类中原本继承于父类的类对象赋值回去,对于派生类对象自己的类对象不会赋值。但是基类对象不能赋值给派生类对象。

如上图,派生类只能将基类中原有的(或者说继承过来的)_name和_gender赋值给父类,其余的无法赋值,如果是引用或指针,也是将派生类中基类对应的对象引用给或地址传给基类,基类修改时,子类也会受影响。

如上图,代码验证。注意,以上代码是在public继承时才会生效,如果换成protected时代码就会报错,protected继承下来的父类对象就是protected而非public,不支持修改的,private继承同理。


1.2父子类类成员变量、函数重名

当父类类成员变量名与子类成员变量名冲突时,默认时优先使用子类的。其实子列中也继承了父类中的重名变量,只不过将其隐藏,可以通过指定类成员名::变量名的方式访问。

再提一点,如果子类中没有实现Print函数而是依靠父类中的Print函数,那么打印结果会是这样的,如下图。

这是因为返回给父类的是一个Person类型的this指针,解引用访问的就是Person类中的_val.


当存在同名的函数名时,子类会调用自身的函数,也可以通过类名指定的方式进行访问。


如上图,这里A::func与B::func关系是隐藏,注意与函数重载区分(函数重载条件是同一作用域内函数名相同,参数列表不同构成重载)。


1.3派生类的默认成员函数

#include <iostream>
using namespace std;
class Person {
public://构造函数Person() :_name("张三") {cout << "Person()" << endl;}//析构函数~Person() {cout << "~Person()" << endl;}//拷贝构造Person(const Person& p1):_name(p1._name) {cout << "Person(copy construct)" << endl;}Person& operator=(const Person& p1) {cout << "operator=" << endl;if (this != &p1) {this->_name = p1._name;}return *this;}public:string _name;
};class Son :public Person {
public:Son(const char* name = "", const string id = "111"):_id(id){}void display() {cout << _name << " " << _id << endl;}
private:string _id;
};int main() {Son s1;s1.display();return 0;
}

子类继承父类时会调用父类的构造函数来初始化继承过来的成员,然后子类在初始化自己的成员,同理对于析构、拷贝构造、赋值重载等都是同理。

如上图,s1会对继承的成员调用其对应的类的构造函数,当然,这也是我没有自定义时会调用父类的构造函数对其进行构造。

那么如何进行自定义构造_name呢?

如上图所示,通过son的构造函数对s1进行实例化构造,但是对于从父类继承下来的_name进行自定义时需要注意的是,在初始化_name时我们不能通过直接初始化的方式进行构造(如38行代码,这是错误的),而是通过父类的构造函数对父类成员进行初始化。在上图中也可以看见代码在初始化列表时(代码36行)就会调用父类的构造函数对_name进行初始化。

当然,也可以不自定义,此时_name就调用父类默认的构造函数对其进行初始化(前提是父类要有全缺省的构造函数,不然代码就会报错)。也可以使用初始化匿名对象的方式完成。

如上图所示,同时也要在父类中定义相对应的构造函数类型。

实现子类对象的拷贝构造函数

如上图,在实现子类的拷贝构造函数时,可以用子类类型的s来实例化Person,(这就是切片:父类可以提取子类中从父类继承来的_name进行初始化通过参数来初始化基类成员)

实现子类对象的赋值重载函数

如上图,实现子类对象的赋值重载函数时需要指明具体是哪一个重载函数,否则就会出现死循环,因为子类和父类出现同名函数时会优先调用子类的函数。代码第61行将Son类对象s进行切片,然后调用父类Person的重载函数将s中父类的部分切给Person完成赋值重载。

1.4继承与友元的关系

如上图所示,父类A的友元函数为display,子类B继承了父类A,此时友元函数只能访问子类的公开成员,对于受保护和私有的则无法访问。

1.5继承与静态成员

如上图,父类A中定义的静态成员变量在整个继承体系中都是存在的。

1.6菱形继承

如下图,A是B和C的父类,D又同时继承了B和C,此时D中含有基类成员_d和父类B(_b)和父类C(_c),同时B和C又同时含有A(_a),因此我们在访问_a时需要指定类域。

在上述图中可见,在开辟空间时,内存中64~68是父类B的空间,其中存放了B::_a和B::_b,对应的值就是1和3;而6C~70是父类C的空间,其中存放的就是C::_a和C::_C,对应的值就是2和4,最后一个位置就是D::_d。

如上图,整个44~54是类对象D的空间。

造成代码冗余与二义性问题

在上述代码中,子类D会同时存储了两份A的继承,分别是继承B和C的,这个就造成了代码冗余与内存消耗;其次当D访问A中成员时必须要指定具体哪个类中的(无法通过d._a方式访问)。解决方法就是虚拟继承。


如上图,通过虚拟继承的方法可以直接访问d._a,其实这里的B和C共享同一分A的继承,也就是说代码第91和92行对_a的修改是对同一个对象的修改(这一点在代码运行过程中可以看出)。

如上图所示,不难发现虽然_a是类中共享的一份区域,但是C和B区域与非虚拟继承相比又多出一块区域(如上图中绿色区域所示)。在分析内存时,0x0078FEAC指向的位置是0x00929bf4,0x0078FEC0指向的位置是0x00929c00,其内存图如下图所示

如上图所示,虽然0x00929bf4与0x00929c00指向的位置内容为空,但是其后一个位置的0000000c从十六进制转换为十进制刚好是12,其实这也就是C到_a的偏移量,这个表叫做虚基表,而只想虚机表的指针叫做虚机表指针。

http://www.dtcms.com/a/589403.html

相关文章:

  • 52_AI智能体运维部署之使用Flask蓝图模块化系统监控服务
  • 【2025-11-07】软件供应链安全日报:最新漏洞预警与投毒预警情报汇总
  • Linux系统笔记--Base
  • RHCE配置主从服务器的实验
  • 中国十大热门网站排名网页加载不出来怎么办
  • Labview封装exe程序
  • 网站用视频做背景音乐小程序商城货源怎么找
  • C/C++输入输出初级(二) (算法竞赛)
  • Windows导入大型sql文件到mysql
  • K8S RD: Kubernetes核心概念与运维实践详解
  • 营销型企业网站测评表wordpress汽车主题
  • Java中文件操作和IO
  • MapTalks:国产轻量化二三维一体化GIS引擎
  • 做html网站wordpress divi安装
  • JS 表单处理与数据校验实战指南:构建安全、流畅的交互体验
  • php网站开发程序编译软件招商网站建设免费
  • 在Rsbuild中使用Rsdoctor
  • 临沂学做网站做网站购买什么软件
  • AIGC|上海AI优化企业新榜单与选择指南
  • 26.分布式系统链路追踪
  • 《Redis应用实例》Java实现(29):优先队列
  • 【FPGA】使用移位和38译码器原理实现LED流水灯
  • 哪些网站用django做的南昌网站设计网站开发
  • GraphQL:让前端自己决定要什么数据
  • 基于非负矩阵分解的复杂网络社区检测研究综述
  • 怎么让网站绑定域名访问广州建筑公司招聘信息
  • Webpack 打包体积优化:让应用更轻量、更高效
  • Webpack 优化:构建速度与包体积的双重提升
  • 基于MATLAB的PCA+SVM人脸识别系统实现
  • 机器学习:支持向量机(SVM)详解