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) {  // 有参构造函数1cout << "Animal(int age)" << endl;}Animal(int age, char gender) :age_(age), gender_(gender) {  // 有参构造函数2cout << "Animal(int age, char gender)" << endl;}
private:int age_;char gender_;
};void test() {Animal animal0;               // 无参构造函数Animal animal1 = 10;          // 有参构造函数1Animal animal2 = { 20,'n' };  // 有参构造函数2Animal 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.hqwc.cn/news/18294.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

云原生监控——VictoriaMetrics

1.简介 VictoriaMetrics是一个快速高效且可扩展的监控解决方案和时序数据库&#xff0c;可以作为Prometheus的长期远端存储&#xff0c;具备的特性有&#xff1a; 支持prometheus查询api&#xff0c;同时实现了一个metricsql 查询语言支持全局查询视图&#xff0c;支持多prom…

在OK3588的Ubuntu系统上安装Firefox浏览器

文章目录 概要配置上网环境安装的具体命令 概要 因为Ubuntu系统里面没有安装浏览器&#xff0c;为了方便使用&#xff0c;提高工作效率&#xff0c;我们安装一下Firefox浏览器。 Firefox是一款适用于Ubuntu系统的免费和开源的Web浏览器。由Mozilla Foundation和其子公司Mozil…

生成图片验证码-Google Kaptcha

CaptchaImage生成 验证码 图片 captchaProducerMath.createText() 类似 captchaProducer.createText() 混合带字符的char如下 从若依学的&#xff0c;先看他的引用方式 package com.ruoyi.web.controller.common;import java.awt.image.BufferedImage; import java.io.IOExcept…

【数据仓库】BI看板DataEase入坑指南

开头夸夸国产开源BI软件DataEase&#xff0c;支持常见各种报表&#xff0c;还支持图表联动和上下级钻取&#xff0c;超赞有木有&#xff01;&#xff01;&#xff01; 再来为什么说入坑&#xff0c;源码启动各种不服啊。本地用的maven3.5一直导入不了Java项目backend。后来看了…

React-Native学习,RN的容器Flex-Box布局

justify-content&#xff08;在RN中属性名称为&#xff1a;justifyContent&#xff09;在主轴上对齐方式 align-items&#xff08;在RN中属性名称为&#xff1a;alignItems&#xff09;在交叉轴上的对齐方式 在React Native中&#xff0c;当没有设置容器的主轴方向时&#xf…

觉非科技李东旻:智能驾驶向大模型的进化与感知决策新范式的诞生

由亿欧汽车主办“AI与新一代车载智能感知融合创新论坛”近日登陆2023世界人工智能大会&#xff08;WAIC&#xff09;。觉非科技CEO李东旻受邀发表了“智能驾驶向大模型的进化与感知决策新范式的诞生”主题演讲&#xff0c;从产业趋势结合技术发展特点以及在感知决策中的能力应用…

【安卓12源码】WMS的作用及其启动流程

一、WMS 的作用 WMS 在 Android 系统的地位&#xff0c;它作为中间层&#xff0c;连接了上层的 View 框架和下层的 SurfaceFingler。 WMS 主要职责 窗口管理&#xff1a;负责启动、添加、删除窗口&#xff0c;管理窗口大小、层级&#xff0c;核心成员有&#xff1a;WindowCont…

Java的Hibernate框架中集合类数据结构的映射编写教程

Java的Hibernate框架中集合类数据结构的映射编写教程 一、集合映射 1.集合小介 集合映射也是基本的映射&#xff0c;但在开发过程中不会经常用到&#xff0c;所以不需要深刻了解&#xff0c;只需要理解基本的使用方法即可&#xff0c;等在开发过程中遇到了这种问题时能够查询…

elementui自定义loading图标

效果图如下&#xff1a; 一、在assets下新建一个mycss.css文件夹&#xff08;图片大小以及文字样式&#xff0c;可以根据自己的需求进行微调&#xff09; .el-loading-spinner {/*这个是自己想设置的 gif 加载动图*/background-image: url(../gif2.gif); background-repeat: n…

redis的分布式事务-redisson

一 redisson 1.1 redisson分布式事务 Redisson分布式锁是一种基于redis实现的分布式锁&#xff0c;它利用redis的setnx命令实现分布式锁的互斥访问。同时还支持锁的自动续期功能&#xff0c;可以避免因为某个进程崩溃或者网络故障导致锁无法释放的情况。 只要线程一加锁成功…

各种好看的css效果收集

CSS动画特效-多种方案实现CSS光束扫过&#xff0c;扫光特效&#xff0c;ae文字过光效果&#xff0c;光效移动效果 一个集合180种免费的线性渐变网站&#xff0c;可在任何网站使用您不仅可以复制渐变的原生CSS颜色代码&#xff0c;还可以查看下载每个优质的渐变图片。 链接&…

第二课:Figma 界面认识

创建文件 进入 Figma 后&#xff0c;可以查看最近浏览的内容&#xff0c;官方也推荐了一些基础的项目&#xff0c;点击右上角 Design file&#xff08;设计文件&#xff09;即可创建项目&#xff1b; 注&#xff1a;网页版和本地版界面样式布局一致。 创建画布 点击左上画框…