C++类相关概念

news2024/9/21 10:33:59

1. 函数形参默认值

 

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

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

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

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

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

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


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.coloradmin.cn/o/729473.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mybati执行流程源码分析

MyBatis执行流程源码分析 前言 由于之前写过关于mybatis源码的文章,但是感觉还是不够细致,不够完善.没有把一些具体的流程应用写下来,至此又写了一篇.内容可能比较长,希望大家可以打开源码跟着这篇文章一起看源码保证可以收获许多. 1.mybatis基础开发流程 1.引入mybatis相关…

短视频去水印小帮手微信小程序源码带后台

短视频去水印小帮手微信​小程序源码​带后台&#xff0c;短视频去水印系列教程服务端源码。 php版&#xff0c;这里不过多介绍&#xff0c;我假设您有基本的编码基础&#xff0c;并熟悉php语言及laravel框架。

Topaz Gigapixel AI v6 人工智能图像放大

其他软件或插件依赖于插值算法来放大图像&#xff0c;Topaz Gigapixel AI 则与众不同&#xff0c;它使用最先进的深度学习技术来扩大和增强图像。 它通过神经网络分析了数百万张照片&#xff0c;从而了解了不同的照片在放大时细节是如何损失的&#xff0c;以及如何为图像增强和…

四十三、贪心——Huffman树、排序不等式

算法主要内容 一、Huffman树1、题目内容——合并果子2、算法思路&#xff08;1&#xff09;“合并果子”中的Huffman树&#xff08;2&#xff09;算法步骤&#xff08;3&#xff09;状态转移 3、题解 二、排序不等式1、题目内容——排队打水2、算法思路&#xff08;1&#xff0…

【MySQL】数据库基础概念

文章目录 前言连接服务器什么是数据库&#xff1f;MySQL和MySQLdLinux中如何看到数据库文件SQL语句分类存储引擎 前言 今天继续讲解MySQL相关内容&#xff0c;本期主要讲解数据库的基础概念&#xff0c;方便后续学习数据库。 连接服务器 mysql -h [ip] -P [port] -u [root] …

IRIS在Linux下通过JDBC操作其他数据库

以前都是在Windows上用cache的SqlGateway通过odbc创建连接操作其他数据库。现在都用Linux了&#xff0c;那么和其他数据进行调用咋办呢。 可以看到是可以创建JDBC的连接的&#xff0c;而Java是跨平台的&#xff0c;所以可以用JDBC操作其他数据库&#xff0c;这次以mysql为例。…

浅谈Node.js中的npm和yarn

官方文档&#xff1a; npmhttps://www.npmjs.cn/ yarnhttps://yarn.bootcss.com/ npm和yarn的作用 yarn和npm都是构建和打包javascript代码的工具 区别 npm&#xff1a; 1npm使得js开发者易于分享其为解决特定问题而编写的代码&#xff0c;且可供其他开发者在他们自己的应…

【阶段学习小总结】

串口通信和CAN总线通信的区别 can总线和串口是两种不同的通信模式&#xff0c;注意CAN总线数据传输所用的虽然是DB9串口线&#xff0c;但它完全不是串口&#xff0c;这一点容易出错。 CAN总线通信是高速&#xff0c;可靠&#xff0c;灵活的一种通信协议。作为一种分布式通信方…

天梯赛注意事项

格式错误 有的时候题目隐含的条件是要你输出两行的&#xff0c;即使第二行什么也没有&#xff0c;也得输出。 答案错误可能涉及特殊值的处理 或者 题意与你本身的思维不一致 map定义在main外面 键自动赋值 it->first it->second mp自动按照下标排序 . 模拟出栈入栈操…

使用GTK创建简易计算器

使用GTK创建简易计算器 本文将介绍如何使用GTK&#xff08;GIMP Toolkit&#xff09;创建一个简单的计算器应用程序。通过这个例子&#xff0c;你将学习如何构建基本的图形用户界面&#xff0c;并了解GTK的一些常用组件和回调函数的使用。 准备工作 首先&#xff0c;确保你已…

Django之中间件

一、中间件介绍 官方的说法&#xff1a;中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统&#xff0c;用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。 但是由于其影响的是全局&#xff0c;所以需要…

Vivado2020.1 vitis使用:创建hello world项目

前言 之前网上的教程都是基于Vivado2018的&#xff0c;后来接手一个未完工的项目&#xff0c;是使用Vivado2020.1创建的&#xff0c;非常尴尬&#xff0c;只能打开&#xff0c;不能编辑。千辛万苦把2020.1安装好&#xff0c;当然此时不仅仅是Vivado2020.1了&#xff0c;而是vi…

gitee注册以及使用的简单教程

目录 1.gitee是什么&#xff1f; 2. gitee怎么注册? 3.gitee创建仓库 4.gitee怎么提交代码? 5. git的三板斧 1.gitee是什么&#xff1f; 基于Git的代码托管和研发协作平台上面可以托管个人或者公司的代码和开源项目。国外有github&#xff0c;国内有giteegithub经常出现…

(vue)el-table表头、内容居中

(vue)el-table表头、内容居中 效果&#xff1a; 表头、内容都居中 <el-table:data"gridData":header-cell-style"{text-align:center}":cell-style"{text-align:center}" >单个表格的内容居中&#xff1a; el-table-column上加上align‘c…

【C++】-string类的模拟实现

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法\&#x1f384; 如 果 你…

抖音seo源码开发部署技术分享(一)

目录 开发概述 自研开发者介绍 开发要求&#xff1a; 技术开发布局 源码部署及搭建分享 部署环境搭建 代码开发示例 请求样例 响应样例&#xff1a; 代码展示样例 开发概述 开放平台基于开发者诉求和相关平台规则&#xff0c;提供了两种开放模式&#xff1a;能力开放…

前端Vue自定义顶部导航栏navBar 导航栏搜索框searchBar 导航栏右侧菜单按钮button

前端Vue自定义顶部导航栏navBar 导航栏搜索框searchBar 导航栏右侧菜单按钮button&#xff0c;下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13342 效果图如下: # cc-headerSearch #### 使用方法 使用方法 <!-- icon: 右侧菜单…

OpenCV在一个图像上画一个空心绿色的圆和一个实心红色的圆

/*** void cvCircle( CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int line_type=8, int shift=0 );* Opencv画点 其实画的是小圆圈* img:图像。* center:圆心坐标。* radius:圆形的半径。* color:线条的颜色。* thickness:如果是正数,表…

vue筛选框封装

点击对默认查询条件之外的条件进行 增加或删除 在使用的组件或标签加入:filtrateList"filtrateList"传入条件查询数组 当前demo写在xk-page中,就以xk-page组件为例 <xk-upage :filtrateList"filtrateList" :queryArr"queryArr"></xk-…

java项目之母婴用品网站(ssm+mysql+jsp)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于ssm的母婴用品网站。 开发环境&#xff1a; 后端&#xff1a; 开发语言&#xff1a;Java 框架&#xff1a;ssm&#xff0c;mybatis JDK版本&am…