C++类相关概念

1. 函数形参默认值

(1) 建议函数(不仅仅是构造函数)形参默认值只在函数声明中指定;

        (函数声明和定义写在同一个文件中,则函数声明、定义两者之一或两者都可指定形参默认值,两者都指定默认值时,默认值需相同;但函数声明写在头文件、定义写在源文件时,只能在函数声明中指定形参默认值。)

(2)函数参数默认值 “一默到底”;

(3)若在调用函数时传入参数,则相应参数会替换掉默认值;

(4)构造函数只能通过初始化列表对const成员变量进行初始化,不可在其函数体中使用赋值语句进行初始化;

(5)注意:C语言不支持函数形参有默认值的特性。


2. 隐式类型转换和explicit

2.1 构造函数隐式类型转换

class Animal {
public:
	Animal() {   // 无参构造函数
		cout << "Animal()" << endl;
	}

	Animal(int age) :age_(age) {  // 有参构造函数1
		cout << "Animal(int age)" << endl;
	}

	Animal(int age, char gender) :age_(age), gender_(gender) {  // 有参构造函数2
		cout << "Animal(int age, char gender)" << endl;
	}
private:
	int age_;
	char gender_;
};

void test() {
	Animal animal0;               // 无参构造函数
	Animal animal1 = 10;          // 有参构造函数1
	Animal animal2 = { 20,'n' };  // 有参构造函数2
	Animal animal3 = (30, 'n');   // 有参构造函数1,写法错误!!!
}

运行结果:

如上示例,animal1和animal2的构造发生了隐式类型转换。

注意:Animal animal3 = (30, 'n')这种写法错误,因为逗号表达式的值为其中最后一个表达式的值,这里发生窄化转换(不同数值类型的转换),相当于使用n来初始化age,所以调用构造函数Animal(int age)。


2.2 explicit关键字

如何禁止调用构造函数时的隐式类型转换?使用explicit关键字修饰构造函数即可。

使用explicit修饰后,需要显式地指定初始化的类型。

如:

class Animal {
public:
	explicit Animal(int age) :age_(age) { 
		cout << "Animal(int age)" << endl;
	}
private:
	int age_;
	char gender_;
};

void test() {
	Animal animal1 = 10;          // 错误,禁止隐式类型转换。
    Animal animal2 = static_cast<Animal>(10);  // 显式地指定初始化的类型
    Animal animal3 = Animal(10);       // 显式地指定初始化的类型
}

建议:

(1)单参数的构造函数声明为explicit;

(2)explicit只在函数声明时添加。


3. 常量成员函数

3.1 const修饰成员函数体

则该成员函数为“常量成员函数”,不可修改对象中的成员变量。

示例:

class Student {
public:
	Student(int id) :id_(id) {
	}

	auto getId() const {
		id_ += 3;  // 错误。不可修改成员
		return id_;
	}

private:
	int id_;
};

3.2 const修饰返回值为引用的成员函数

则返回的引用不能被修改。

示例:

class Student {
public:
	Student(int id) :id_(id) {
	}

	const auto& getId() const {
		// id_ += 3; 错误。不可修改成员
		return id_;
	}

private:
	int id_;
};

void test01() {
	Student s0(16);
	// s0.getId() += 3; 错误。不可修改返回的引用
	cout << s0.getId() << endl;
}

注意:该返回值为引用的成员函数被两个const修饰,

第一个const表示返回的引用不能被修改,第二个const表示函数体中不能修改对象成员。


3.3  const对象只能调用const成员函数,非const对象可调用const成员函数

示例:

class Student {
public:
	Student(int id, string name) :id_(id),name_(name) {
	}

	int getId() const {    // const成员函数
		return id_;
	}

	string getName() {    // 非const成员函数
		return name_;
	}

private:
	int id_;
	string name_;
};

void test01() {
	const Student s0(16,"ABC");    // const对象
	cout << s0.getId() << endl;    // 正确。const对象可调用const成员函数
	cout << s0.getName() << endl;  // 错误。const对象不可调用非const成员函数

	Student s1(20, "XYZ");         // 非const对象
	cout << s1.getId() << endl;    // 正确。非const对象可调用const成员函数
	cout << s1.getName() << endl;  // 正确。非const对象可调用非const成员函数
}

(1)非const对象可调用const、非const成员函数;

(2)const对象只可调用const成员函数;

(3)const成员函数可被const、非const对象调用;

(4)非const成员函数只可被非const对象调用。


注意:普通函数(非类成员函数)不能用const修饰!

如下错误!

void func() const {  // 错误。普通函数不能用const修饰
}

4. mutable

则const成员函数可修改mutable修饰的成员变量。

class Student {
public:
	Student(int id, string name) :id_(id),name_(name) {
	}

	void setId(int id) const {  // 可修改mutable成员
		id_ = id;
	}

private:
	mutable int id_;
	string name_;
};

5. this指针

(1)普通成员函数隐藏一个this指针,该指针指向调用函数的对象;

(2)this指针只能在普通成员函数中使用,全局函数、static函数不能使用this指针;

(3)非const成员函数,this指针是一个指向非const对象的指针常量;

        (意思是:非const对象只可调用非const成员函数;并且this指针的指向不能改变)


6. static成员

(1)static全局变量:保存在静态区,作用域为当前文件,无法在其他文件使用(使用extern声明也无法使用);

(2)static成员函数只能访问static成员变量;

(3)static成员变量在类内定义,类外初始化;

类外初始化时不必加static关键字。

如下:

class Student {
private:
    int id_;    
    static int a_;       // 类内定义static成员变量
    static void setA();  // 类内定义static成员函数
}


/* 类外初始化static成员变量、函数 */
int Student::a = 10;  // 初始化时不必加static关键字;不给初值则为0.
void Student::setA() {
	a_ = 99;      // 正确,static成员函数可访问static成员变量
	// id_ = 88;  // 错误,static成员函数不可访问非static成员变量
}

 (4)static成员变量或函数属于类,为该类所有对象共享;

访问方式:

class Student {
public :
    static int a;
    static void setA();
};

int Student::a = 10;
void Student::setA() {
	a = 99;
}

void test02() {
    Student s0(20, "AAA");
	Student::a;       // 通过类访问static成员变量
	s0.a;             // 通过对象访问static成员变量
    Student::setA();  // 通过类访问static成员函数
	s0.setA();        // 通过对象访问static成员函数
}

7. 拷贝构造函数

用一个已存在的对象初始化新对象,会调用拷贝构造函数。

(1)拷贝构造函数的第一个形参必须是该类类型的引用,可以没有其他参数;若有其他参数,则其他参数必须有默认值。如:

Student(const Student& s, int age = 18);

(2)拷贝构造函数不建议使用explicit修饰;


8. 隐藏

概念:

派生类中有与基类同名(参数列表可不同)的成员函数,则基类中的该同名成员函数在派生类中不可见(不可调用)。

实例1:派生类中无与基类同名的成员函数。

class Person {
public:
	void run() {
		cout << "Person::run()" << endl;
	}

	void run(int a) {
		cout << "Person::run(int a)" << endl;
	}
};

class Student :public Person {
};

void test() {
    Student s;
	s.run();   // 正常调用
	s.run(3);  // 正常调用
}

示例2:派生类中有与基类同名的成员函数,发生隐藏。

class Person {
public:
	void run() {
		cout << "Person::run()" << endl;
	}

	void run(int a) {
		cout << "Person::run(int a)" << endl;
	}
};

class Student :public Person {
public:
	void run(string s) {
		cout << "Student::run(string s)" << endl;
	}
};

void test() {
	Student s;
	s.run("ABC");    // 正常调用
	s.run();         // 不可调用基类的run()
	s.run(3);        // 不可调用基类的run(int)
}

发生隐藏时,如何调用基类同名的成员函数?

方式1:在派生类的同名成员函数中调用基类的同名成员函数。(遵循访问权限规则)

class Student :public Person {
public:
	void run() {
		Person::run();
	}
};

方式2:C++ 11中using关键字可让基类同名成员函数在派生类中可见。(让基类的同名成员函数在派生类中以重载的方式使用,遵循访问权限规则)

注意: 使用using时只能指定函数名,无需参数列表。

class Person {
public:
	void run() {
		cout << "Person::run()" << endl;
	}

	void run(int a) {
		cout << "Person::run(int a)" << endl;
	}
};

class Student :public Person {
public:
	void run(string s) {
		cout << "Student::run(string s)" << endl;
	}

public:
	using Person::run;  // 只能指定函数名
};

void test() {
	Student s;
	s.run();         // 可调用基类的run()
	s.run(13);       // 可调用基类的run(int)
}

9. 虚函数相关

9.1 override 修饰派生类中的虚函数

建议在派生类虚函数后加关键字override,避免虚函数名、返回值类型、参数列表写错。

/*派生类中的虚函数*/
virtual void func() override {
	cout << "Derive::func()" << endl;
}

9.2 final 修饰基类中的虚函数

final修饰基类中的虚函数,禁止在派生类中重写。

/*基类中的虚函数*/
virtual void func() final {
	cout << "Base::func()" << endl;
}

9.3 建议将基类的析构函数写成虚函数


待补充。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/37492.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

中国移动光猫设置桥接

网上教程五花八门&#xff0c;有些坑有些行&#xff0c;我试成功了&#xff0c;记录一下方法。 一、流程简述 1. 使用超级管理员账号登录中国移动光猫&#xff0c;设置桥接&#xff0c;并重启 2. 用网线连接路由器和光猫&#xff0c;登录路由器&#xff0c;设置宽带拨号&…

数据分析——AB测试应用与实战

摘要 某电商公司非常注重自己的落地页设计&#xff0c;希望通过改进设计来提高转化率。以往该公司全年转化率平均在13%左右&#xff0c;现在希望设计的新页面能够带来更高的转化率&#xff0c;希望新页面的转化率能有2%的提升&#xff0c;达到15%。在正式推出新页面之前&#…

【Distributed】分布式ELK日志文件分析系统(二)

文章目录 一、FilebeatELK 部署1. 环境部署2. 在 Filebeat 节点上操作2.1 安装 Filebeat2.2 设置 filebeat 的主配置文件 3. 在 Apache 节点上操作3.1 在 Logstash 组件所在节点上新建一个 Logstash 配置文件 3. 启动3.1 在Logstash 组件所在节点启动3.2 在 Filebeat 节点 启动…

Python调用ImageMagick生成PDF文件缩略图

使用Python调用ImageMagick生成PDF文件缩略图 Imagemagick使用Ghostscript作为其依赖项之一&#xff0c;以便能够处理和转换PDF相关的图像。 准备 安装Ghostscript&#xff0c;网站安装ImageMagick&#xff0c;网站 安装完毕后&#xff0c;需要自行配置环境路径 脚本 使用示…

【USRP X310】如何将你的X310转化为USRP RIO 可以用于FPGA编程

X310 转化为USRP RIO X310产品X310和NI-USRP对应关系 简介第一步原理解释打开工具运行 Initialize Flash.vi可以去选择设备类型Hardware Current Version 如何选择 第二步创建工程运行校准程序 附录&#xff1a;射频子板的IDWBXSBXCBXUBXTwinRX X310产品 X310和NI-USRP对应关系…

jvm新生代调优

5-4 新生代调优 只有排除了自己代码的问题后&#xff0c;再进行内存调优&#xff0c;内存调优都是从新生代开始&#xff0c;因为新生代优化空间更大一些 新生代的特点 所有的new操作分配内存都是非常廉价的&#xff0c;非常快 TLAB&#xff1a;thread-local allocation buf…

Redis——基础篇(包含redis在云服务上的docker化安装和连接以及常用命令)

初识Redis Redis为键值型数据库&#xff0c;数据以键值形式存储。没有表&#xff0c;没有约束。 认识NoSQL mysql就是典型的关系型数据库(SQL)。 目的都是数据的增删改查&#xff0c;但数据存储方式不一样。 关系型和非关系型在结构上有差异 关系型的结构一般定好后就很少修…

【JAVAEE】JVM中垃圾回收机制 GC

博主简介&#xff1a;想进大厂的打工人博主主页&#xff1a;xyk:所属专栏: JavaEE初阶 上篇文章我们讲了java运行时内存的各个区域。 传送门&#xff1a;【JavaEE】JVM的组成及类加载过程_xyk:的博客-CSDN博客 对于程序计数器、虚拟机栈、本地方法栈这三部分区域而言&#x…

动态规划01背包之1049 最后一块石头的重量 II(第9道)

题目&#xff1a; 有一堆石头&#xff0c;用整数数组 stones 表示。其中 stones[i] 表示第 i 块石头的重量。 每一回合&#xff0c;从中选出任意两块石头&#xff0c;然后将它们一起粉碎。假设石头的重量分别为 x 和 y&#xff0c;且 。那么粉碎的可能结果如下&#xff1a; …

微信小程序(二)

目录 1、input标签 一、表单绑定 1、数据绑定 2、输入获取 二、网络请求 1、介绍 2、注意 3、使用 4、基于Promise封装 三、自定义组件 1、创建 2、父向子组件通信 3、子向父组件通信 4、生命周期 四、vant weapp组件库 1、配置 2、使用 进入本章前的拓展&#…

Git❀详细使用教程

Git❀详细使用教程 一、Git简介1.1 什么是Git&#xff1f;1.2 Git的特点1.3 集中式与分布式的区别&#xff1f;1.4 Git工作流程图 二、Git安装与常用命令2.1 Git环境配置2.1.1 下载与安装2.1.2 基本配置2.1.3 为常用指令设置别名&#xff08;可选&#xff09;2.1.4 解决GitBash…

jsonschema networknt json-schema-validator 高级能力json 数字很大时, 变成什么类型

入参校验产品化 schema_个人渣记录仅为自己搜索用的博客-CSDN博客 自动变成了bigInteger类型. 哪怕你的jsonSchema 配置的是integer , 不冲突.

AlGaN基深紫外FP激光器仿真模型及材料信息数据库有何用途?

波长范围为UVC波段&#xff08;100-280 nm&#xff09;的深紫外FP&#xff08;Fabry-Pero&#xff0c;法布里和珀罗是两位法国的科学家&#xff09;激光器可广泛应用于数据通信、光通信、3D打印、材料加工、显示与照明、激光雷达、人脸/手势识别、医疗和表面监测等领域。FP激光…

2023年Q2京东冰箱行业品牌销售排行榜(京东销售数据分析)

近年我国的冰箱零售呈波动变化的趋势&#xff0c;由于冰箱市场趋于饱和&#xff0c;因此消费者对冰箱的需求逐渐变为替换需求&#xff0c;这也进一步推动了产品的更新迭代。接下来结合具体数据&#xff0c;我们来分析一下2023年Q2冰箱行业的销售详情。 根据鲸参谋电商数据分析平…

SpringBoot+Vue实现的高校图书馆管理系统

项目描述&#xff1a;这是一个基于SpringBootVue框架开发的高校图书馆管理系统。首先&#xff0c;这是一个前后端分离的项目&#xff0c;代码简洁规范&#xff0c;注释说明详细&#xff0c;易于理解和学习。其次&#xff0c;这项目功能丰富&#xff0c;具有一个高校图书馆管理系…

6.2.5 网络基本服务----动态主机配置协议DHCP

6.2.5 网络基本服务----动态主机配置协议DHCP 动态主机配置协议允许一台计算机加入新的网络时可自动获取网络配置信息&#xff0c;不用人工参与。连网的计算机需要配置的参数包括 IP地址子网掩码默认路由器的IP地址域名服务器IP地址 DHCP与DNS、FTP、Telnet一样也采用客户服…

Lua脚本本地调试

这里主要使用日志的方式进行debug 环境依赖 项目对openresty包的依赖比较高&#xff0c;所以环境基础都在openresty下进行 openresty的使用 openresty下载地址 下载完成后解压&#xff0c;具体使用方式和nginx没有什么区别&#xff0c;主要依赖文件是一下几个 nginx.exe …

搬家送货小程序开发源码定制一键报警实时定位路线规划

1.货物信息录入&#xff1a; 用户可以输入货物的名称、数量、重量、尺寸等信息。 2.路线选择&#xff1a; 用户可以选择起始地点和目的地点&#xff0c;并根据需求选择最佳路线。 提供地图服务或第三方路径规划服务&#xff0c;以帮助用户确定最佳路线。 3.车辆选择&#…

基于深度学习的高精度鸡蛋检测识别系统(PyTorch+Pyside6+YOLOv5模型)

摘要&#xff1a;基于深度学习的高精度鸡蛋检测识别系统可用于日常生活中或野外来检测与定位鸡蛋目标&#xff0c;利用深度学习算法可实现图片、视频、摄像头等方式的鸡蛋目标检测识别&#xff0c;另外支持结果可视化与图片或视频检测结果的导出。本系统采用YOLOv5目标检测模型…

跨域问题解决

由于同源策略&#xff0c;需要协议&#xff0c;域名&#xff0c;端口三个都相同才能进行访问&#xff0c;是一种浏览器的保护策略 CORS:Cross Origin Resource Sharing SpringBoot 项目中解决跨域 1.在目标方法中加入CrossOrigin注解 2.添加一种过滤器 分别是允许哪些域&#…
最新文章