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

13.继承(一)

一.继承的概念及定义

1.继承的概念

继承的本质就是进行复用

2.继承定义

class Person
{
public:void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;}
protected:string _name = "peter"; // 姓名int _age = 18;  // 年龄
};// 继承后父类的Person的成员(成员函数+成员变量)都会变成子类的一部分。这里体现出了
// Student和Teacher复用了Person的成员。下面我们使用监视窗口查看Student和Teacher对象,可
// 以看到变量的复用。调用Print可以看到成员函数的复用。
class Student : public Person
{
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Student s;Teacher t;s.Print();t.Print();return 0;
}

3.继承方式的探讨

class Person
{
public:Person(){}void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;//cout << _tel << endl;}string _name = "peter"; // 姓名
protected:int _age = 18; // 年龄//...
private:// 父类定义本质,不想被子类继承int _tel = 110;};// 继承的父类的成员
class Student : public Person
{
public:void func(){// 子类用不了(不可见)// cout << _tel << endl;// 子类可以用cout << _name << endl;cout << _age << endl;}
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Person p;p.Print();Student s;s.Print();//s._name = "张三";Teacher t;//t._name = "张老师";return 0;
}

定义成为保护的(protected),对于类外面的(不能直接使用),对于子类而言(我们能使用protected的)

实践中,最常用的就是下面的方式

二.基类和派生类对象赋值转换

我们这里就理解是(多的能转换到少的地方,多的部分就不要就行了)

class Person
{
public:Person(){}void Print(){cout << "name:" << _name << endl;cout << "age:" << _age << endl;//cout << _tel << endl;}string _name = "peter"; // 姓名
protected:int _age = 18; // 年龄//...
private:// 父类定义本质,不想被子类继承int _tel = 110;};// 继承的父类的成员
class Student : public Person
{
public:void func(){// 子类用不了(不可见)// cout << _tel << endl;// 子类可以用cout << _name << endl;cout << _age << endl;}
protected:int _stuid; // 学号
};class Teacher : public Person
{
protected:int _jobid; // 工号
};int main()
{Student s;Person p;// 跟下面机制不一样// 特殊语法规则:不是类型转换,中间没有产生临时变量p = s;Person* ptr = &s;Person& ref = s;ptr->_name += 'x';ref._name += 'y';s._name += 'z';int i = 1234;printf("%x\n", i);// 类型转换// 截断char ch = i;printf("%x\n", ch);// 提升i = ch;printf("%x\n", i);const char& refch = i;return 0;
}

因为  ptr  ,  ref  和  s 操作的是同一个东西

三.继承中的作用域

1.作用域讲解

// Student的_num和Person的_num构成隐藏关系,可以看出这样代码虽然能跑,但是非常容易混淆
class Person
{
protected:string _name = "小李子"; // 姓名int _num = 111;         // 身份证号
};class Student : public Person
{
public:void Print(){cout << " 姓名:" << _name << endl;cout << " 身份证号:" << Person::_num << endl;cout << " 学号:" << _num << endl;}protected:int _num = 999; // 学号
};void Test()
{Student s1;s1.Print();
};

我们可以看到,在这里,我们Person和Student类中都有_num变量

当我们要访问的时候,到底是访问谁的呢?

没有就向上查找(没有就到,全局域进行查找)

2.题目判断

答案选择: B 

class A
{
public:void fun(){cout << "func()" << endl;}
};class B : public A
{
public:void fun(int i){cout << "func(int i)->" << i << endl;}
};// 下面哪个是正确的()
// fun构成重载
// fun构成隐藏
// fun构成重写
// 编译报错
// 运行报错int main()
{B bb;bb.fun();return 0;
}

答案选择: B D

四.派生类的默认成员函数

1.构造函数

class Person
{
public:Person(const char* name = ""): _name(name){cout << "Person()" << endl;}Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}~Person(){cout << "~Person()" << endl;}
protected:string _name; // 姓名
};class Student : public Person
{
protected:int _x;string _address;
};// 父类成员(整体) -- 默认构造
// 子类自己的内置成员 -- 一般不处理
// 子类自己的自定义成员 -- 默认构造int main()
{Student s;return 0;
}

父类的已经写好了构造函数了(所以必定要调用父类的构造函数)

2.拷贝构造

Person(const Person& p): _name(p._name){cout << "Person(const Person& p)" << endl;}Student(const Student& st):Person(st),_x(st._x), _address(st._address){}

3.赋值(operator=)

Person& operator=(const Person& p){cout << "Person operator=(const Person& p)" << endl;if (this != &p)_name = p._name;return *this;}Student& operator=(const Student& st){if (this != &st){Person::operator=(st);_x = st._x;_address = st._address;}return *this;}

4.析构函数

我们要是写呢?

~Person(){cout << "~Person()" << endl;delete[] _str;}// 由于多态,析构函数的名字会被统一处理成destructor()// 父类析构不能显示调用,因为显示调用不能保证先子后父~Student(){// 析构函数会构成隐藏,所以这里要指定类域//Person::~Person();cout << "~Student()" << endl;// delete [] _ptr;cout << _str << endl;}

我们子类不能调用父类的析构函数

但是,我们运行看到

析构函数会有一个机制(自动调用)

(其他的都要进行显示调用,但是析构函数是自动调用的)

C++永远是保证(构造函数)先父后子(继承父类,那么父类就在定义的最开始)(不是按照初始化列表顺序开始的)

析构的时候,是先子后父,所以父类的析构不是自己显示调用的,(子类析构结束后,自动调用)

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

相关文章:

  • vue3:el-progress的圆形无线滚动,心跳、呼吸效果,加载中的效果
  • 高速光耦:电子系统的卓越赋能者
  • 鸿蒙HAP文件数字签名提取与解析
  • 《宋代水墨国漫3D:动态镜头笔触连贯的开发拆解》
  • Fast-Agent:重新定义AI Agent开发的“快“与“简“
  • 做电力的系统集成公司网站个人简历在线制作免费
  • 如何查网站是那家做的用什么做视频网站比较好的
  • SQL UPDATE 语句详解
  • 一个基于BiTCN-BiLSTM混合神经网络的时间序列预测MATLAB程序
  • Python开发的自我修养之数据类型的选择策略
  • Day02_刷题niuke20251017
  • [嵌入式系统-135]:主流AIOT智能体开发板
  • 设计模式---观察者模式
  • 【软考备考】 高并发场景如何做负载均衡知识点四
  • LOFAR物理频谱特征提取及实现
  • excel拼接数据库
  • 23ICPC杭州vp补题
  • 做网站不难吧长兴网站建设
  • Kafka、ActiveMQ、RabbitMQ、RocketMQ 对比
  • Unity中UI背景的高斯模糊
  • Avalonia 的命令基类和通知基类备份
  • 分布式和微服务的区别是什么?
  • windows10 安装 WSL2 及 ubuntu 24.04,Ubuntu中安装CUDA
  • 全链路智能运维中的多模态数据融合与语义对齐技术
  • 【DevOps】基于Nexus部署内网pypi代理镜像仓库操作手册
  • 微服务核心
  • 网站倒计时如何做自己的影视网站
  • 【DevOps】基于Nexus部署内网ubuntu 2204系统APT代理镜像仓库操作手册
  • 【开题答辩实录分享】以《开题报告 智能家居控制平台的构建》为例进行答辩实录分享
  • 建设论坛网站视频稿定设计官网入口