C++(学习)2024.9.25

ops/2024/12/23 1:19:25/

目录

继承

概念

构造函数

1.派生与基构造函数的关系

2.解决方案

(1)补充基的无参构造函数

(2)手动在派生中调用基构造函数

1.透传构造

2.委托构造

3.继承构造

3.对象的创建与销毁流程

4.多重继承

(1)概念

(2)可能出现的问题

1.重名问题

2.菱形继承

权限

1.权限修饰符

2.不同权限的继承

(1)公有继承

(2)保护继承

(3)私有继承


继承

概念

继承就是面向对象的三大特性之一,体现了代码复用的思想。
继承就是在一个已存在的的基础上,建立一个新的,并拥有其特性。
1.已存在的被称为“基”或者“父
2.新建立的被称为“派生”或者“子

#include <iostream>
using namespace std;// 基
class Father
{
private:string name = "张";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生
class Son:public Father
{
};int main()
{Son son;cout << son.get_name() << endl;son.work();return 0;
}

上面的代码,Son的功能几乎与Father重叠,在实际的使用过程中,派生会做出一些与基的差异化。
●修改继承来的基内容
属性:

1、公有属性可以直接更改。更改后基中的属性也会改变,因为改的是同一份变量        

2、私有属性,需要使用基公有函数进行更改。
行为:函数隐藏,通过派生实现一个同名同参数的函数,来隐藏基的函数。
●新增派生的内容

#include <iostream>
using namespace std;// 基
class Father
{
private:string name = "张";
public:void set_name(string name){this->name = name;}string get_name(){return name;}void work(){cout << "我的工作是厨师,我负责炒菜" << endl;}
};// 派生
class Son:public Father
{
public:void init(){set_name("王");}void work(){cout << "我的工作是司机" << endl;}void game(){cout << "开挖掘机" << endl;}
};int main()
{Son son;son.init();cout << son.get_name() << endl;son.work(); son.game();son.Father::work();return 0;
}

        基和派生都是相对的,一个可能存在又是基又是派生的情况,取决于那两个进行比较。

构造函数

1.派生与基构造函数的关系

构造函数与析构函数不能被继承。

#include <iostream>
using namespace std;// 基
class Father
{
private:string name;
public:Father(string name):name(name){}    // 有参构造函数string get_name(){return name;}
};// 派生
class Son:public Father
{
};int main()
{
//    Son s;    // 找不到基的无参构造函数
//    Son s("张"); // 找不派生的有参构造函数return 0;
}

2.解决方案

(1)补充基的无参构造函数
#include <iostream>
using namespace std;// 基
class Father
{
private:string name;
public:// 无参构造函数Father():name("张"){}// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生
class Son:public Father
{
public:
};int main()
{Son s;    cout << s.get_name() << endl;return 0;
}
(2)手动在派生中调用基构造函数
1.透传构造

在派生的构造函数中,调用基的构造函数,实际上编译器自动添加的派生构造函数,调用基无参构造函数时,就是采用的这种方式。

#include <iostream>
using namespace std;// 基
class Father
{
private:string name;
public:// 有参构造函数Father(string name):name(name){}string get_name(){return name;}
};// 派生
class Son:public Father
{
public:// 编译器会自动添加构造函数,透传调用基无参构造函数(透传构造)// Son():Father(){}// 手动添加构造函数,透传构造Son():Father("王"){}// 有参构造函数,调用基有参构造函数Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;Son s1("张");cout << s1.get_name() << endl;return 0;
}
2.委托构造

一个的构造函数可以调用这个的另一个构造函数,但是需要避免循环委托。

        委托构造的性能低于透传构造,但是代码的“维护性更好”,因为通常一个中构造函数都会委托给能力最强(参数最多)的构造函数。代码重构时,只需要更改这个能力最强的构造函数即可。

#include <iostream>
using namespace std;// 基
class Father
{
private:string name;
public:Father(string name):name(name){}    // 有参构造函数string get_name(){return name;}
};// 派生
class Son:public Father
{
public:Son():Son("李"){}    // 委托构造Son(string fn):Father(fn){}    // 有参构造函数,调用基有参构造函数
};int main()
{Son s;cout << s.get_name() << endl;Son s1("赵");cout << s1.get_name() << endl;return 0;
}
3.继承构造

C++11新增的写法,只需要一句话,就可以自动给派生添加n(n个为基构造函数的个数)个构造函数。并且每个派生的构造函数格式都与基相同,每个派生的构造函数都通过透传构造调用对应格式的基构造函数。

#include <iostream>
using namespace std;// 基
class Father
{
private:string name;
public:Father():Father("张"){}Father(string name):name(name){}    // 有参构造函数string get_name(){return name;}
};// 派生
class Son:public Father
{
public:using Father::Father;// 只需要补充这一句话,编译器就会自动添加下面两种构造函数    // Son():Father(){}// Son(string fn):Father(fn){}
};int main()
{Son s;cout << s.get_name() << endl;Son s1("王");cout << s1.get_name() << endl;return 0;
}

3.对象的创建与销毁流程

在继承中,构造函数与析构函数是有一定调用顺序的。

#include <iostream>
using namespace std;class Value
{
private:string str;
public:Value(string str):str(str){cout << str<< " 调用Value构造函数" << endl;}~Value(){cout << str << " 调用Value析构函数" << endl;}
};class Father
{
public:static Value s_value;Value val = Value("Father 成员变量");Father(){cout << "Father 构造函数被调用了" << endl;}~Father(){cout << "Father 析构函数被调用了" << endl;}
};
Value Father::s_value = Value("静态FatherValue");class Son:public Father
{
public:static Value s_value;Value val = Value("Son成员变量");Son(){cout << "Son 构造函数被调用了" << endl;}~Son(){cout << "Son 析构函数被调用了" << endl;}
};
Value Son::s_value = Value("静态SonValue");int main()
{cout << "主函数被调用了" << endl;// 局部代码块{Son s;cout << "对象执行中" << endl;}cout << "主函数结束了" << endl;return 0;
}

上面的执行结果中,可以得到以下的规律:
(1)静态的创建早于非静态。
(2)在创建的过程中,同型的内存空间基先开辟,派生先销毁。创建对象时:先基后派。销毁对象时:先派后基
(3)以“对象执行中为轴”上下对称

4.多重继承

(1)概念

        C++支持多重继承,即一个派生可以有多个基,派生对于每个基的关系仍然可以看作是一个单继承。

#include <iostream>
using namespace std;class Sofa
{
public:void sit(){cout << "可以坐着" << endl;}
};class Bed
{
public:void lay(){cout << "可以躺着" << endl;}
};// 派生
class SofaBed:public Sofa,public Bed
{
};int main()
{SofaBed sobe;sobe.lay();sobe.sit();return 0;
}
(2)可能出现的问题
1.重名问题

当多个基具有重名成员时,编译器在编译的时候会出现二义性问题。
解决方法:使用名::方式调用

#include <iostream>
using namespace std;class Sofa
{
public:void sit(){cout << "可以坐着" << endl;}void clean(){cout << "打扫沙发" << endl;}
};
class Bed
{
public:void lay(){cout << "可以躺着" << endl;}void clean(){cout << "打扫床" << endl;}
};// 派生
class SofaBed:public Sofa,public Bed
{
};int main()
{SofaBed sobe;sobe.lay();sobe.sit();sobe.Sofa::clean();sobe.Bed::clean();return 0;
}
2.菱形继承

        当一个派生有多个基,且这些基又有一个共同的基,就会出现二义性的问题,这种现象被称为(钻石)菱形继承。

有两种解决方式:
1、和重名问题似,使用基名::方式调用

2、使用虚继承
当出现虚继承时,Furniture中就会生成一张虚基表,这个表不占用任何对象的存储空间,属于Furniture持有,在程序启动时加载进内存空间,表中记录了Furniture函数的调用地址偏移量。
Bed和Sofa对象中会出现一个隐藏的成员变量指针,指向Furniture中的虚基表,占用对象的四个字节。
虚继承时,SofaBed对象会同时拥有两个虚基表指针成员,在调用时查表解决二义性。

#include <iostream>
using namespace std;// 家具厂
class Furniture
{
public:void func(){cout << "家具厂里有家具" << endl;}
};class Sofa:virtual public Furniture
{
};
class Bed:virtual public Furniture
{
};// 派生
class SofaBed:public Sofa,public Bed
{
};
int main()
{SofaBed sobe;sobe.func();return 0;
}

权限

1.权限修饰符

派生全局(外)
private√ ××
protected√ √ ×
public√ √ √ 
#include <iostream>
using namespace std;class Test
{
protected:string str="保护权限";
public:Test(){cout<<str<<endl;}
};class Base:public Test
{
public:Base(){cout<<str<<endl;}};int main()
{Base b;//cout<<b.str<<endl;// 错误 b是保护权限return 0;
}

2.不同权限的继承

(1)公有继承

        公有继承是使用最多的一种继承方式,在公有继承中,派生可以继承基的成员,但是不可以访问基的私有成员,基成员的权限在派生中权限保持不变。

#include <iostream>
using namespace std;class Base
{
private:string str1 = "私有成员";
protected:string str2 = "保护成员";
public:string str3 = "公有成员";
};class Son:public Base
{
public:Son(){//       cout << str1 << endl;      // 错误 str1为私有成员cout << str2 << endl;cout << str3 << endl;}
};int main()
{Son s1;return 0;
}

(2)保护继承

        在保护继承中,派生可以继承基的成员,不可以访问基的私有成员,基的公有成员与保护成员,在派生的权限都是保护权限。

#include <iostream>
using namespace std;class Base
{
private:string str1 = "私有成员";
protected:string str2 = "保护成员";
public:string str3 = "公有成员";
};
class Son:protected Base
{
public:Son(){//cout << str1 << endl;     // 错误 str1为私有成员cout << str2 << endl;cout << str3 << endl;}
};int main()
{Son s1;//    cout << s1.str3 << endl; // 保护成员调用失败return 0;
}

(3)私有继承

        在私有继承中,派生可以继承基的成员,但是不可以访问基的私有成员,基的公有成员与保护成员在派生中权限都是私有权限。

#include <iostream>
using namespace std;class Test
{
private:string str1="私有成员";
protected:string str2="保护成员";
public:string str3="公有成员";
};class Base:private Test
{
public:Base(){//        cout<<str1<<endl;cout<<str2<<endl;cout<<str3<<endl;}
};
class Demo:public Base
{
public:Demo(){cout << str2 << endl;cout << str3 << endl;}
};int main()
{Base b;
//    cout<<b.Test::str3<<endl;return 0;
}

http://www.ppmy.cn/ops/120159.html

相关文章

React【vite使用模块化css】

文章目录 前言一、使用步骤1.vite初始化react项目2. 安装sass3. 增加声明文件4.配置ts.config.json5.使用 二、scss文件默认支持模块化&#xff0c;而无需加.module 前言 一般编写组件样式的时候我们都需要做对样式的模块化&#xff0c;以防止组件样式间的样式污染。 在vue中有…

vue2+keep-alive h5端 从首页进入客户列表-客户列表更新,从客户列表进入客户详情再返回,客户列表需要缓存筛选条件以及滚动位置

确保 路由层级是2级 在app.vue 添加如下代码 <keep-alive :include"include"><!--带 keepAlive 的标识页面进行缓存 从详情列表再进来会更新或者自己手动更新--><router-view v-if"$route.meta.keepAlive "></router-view></…

uni-app - - - - -vue3使用i18n配置国际化语言

uni-app - - - - -使用i18n配置国际化语言 1. 安装vue-i18n2. 配置文件2.1 创建如下文件2.2 文件配置2.3 main文件导入i18n 3. 页面内使用3.1 template内直接使用3.2 变量接收使用 1. 安装vue-i18n npm install vue-i18n --save2. 配置文件 2.1 创建如下文件 locales文件夹里…

DC00020基于springboot新闻网站系统java web项目MySQL新闻管理系统

1、项目功能演示 DC00020基于springboot新闻网站系统java web项目MySQL 2、项目功能描述 基于springbootvue新闻网站包括用户和系统管理员两个角色。 2.1 用户功能 1、用户登录、用户注册 2、新闻信息&#xff1a;点赞、点踩、收藏、查看 3、用户分享&#xff1a;点赞、点踩…

猫咪尿闭的症状有哪些?适合尿闭猫咪的猫罐头盘点

刚开始养猫的时候只喂猫粮&#xff0c;也没督促孩子喝水&#xff0c;也没喂猫罐头&#xff0c;结果猫咪尿闭了&#xff0c;每次上厕所都在惨叫&#xff0c;完全无法排尿。带去医院治疗&#xff0c;前前后后总共花了8000&#xff0c;真实花钱买教训。我总结了一下猫咪尿闭时会出…

点评项目-2-完善注册登录业务

业务一&#xff1a;向手机发送验证码 需要处理的业务&#xff1a;在网页发送 /user/code 路径下的 post 请求后&#xff0c;我们需要检验手机号后&#xff0c;向合法的手机号发送一个随机生成的电话号 第一步&#xff1a;UserController RestController RequestMapping(&quo…

记录docker phpadmin 链接 docker mysql

1&#xff1a;正常使用docker 拉取mysql 镜像&#xff0c;容器名字为&#xff1a;mysql888 &#xff0c;配置好 【你的root密码】 2&#xff1a;正常使用docker 拉取phpadmin镜像 3 &#xff1a;执行&#xff1a;docker run --name myadmin -d --link mysql888:db -p 8898:80…

针对考研的C语言学习(2019链表大题)

题目解析&#xff1a; 【考】双指针算法&#xff0c;逆置法&#xff0c;归并法。 解析&#xff1a;因为题目要求空间复杂度为O(1)&#xff0c;即不能再开辟一条链表&#xff0c;因此我们只能用变量来整体挪动原链表。 第一步先找出中间节点 typedef NODE* Node; Node find_m…