C++类复习

C++类

1. 类内成员函数隐式声明为inline

class Str {int x;int y = 3;
public:inline void fun(){std::cout<<"pf,yes!"<<std::endl;}
};

这段代码不会报错,但是类内的成员函数隐式声明为inline函数,不需要单独写在前面。因此将成员函数在类的内部实现是最保险的写法。

2. 全局函数上使用inline。

inline int Add(int x, int y) {return x + y;
}

这是全局函数上使用inline函数。

同样,上述代码可以写在头文件之中,或写在源文件之中,如果不使用 inline,那么写在头文件之中被多个源文件 include 那么就会导致符号重定义冲突,单个源文件引入却不会。

3. inline关键字的作用

  1. 可以在任意的函数定义的时候使用;

  2. 建议编译器使用内嵌的方式优化代码;

  3. inline函数,由调用的函数的源文件实现;

使用使用内联展开,取决于函数的复杂程度

以下的函数使用inline也不会被优化

1、函数指针或函数引用

2、复杂的 inline 函数体

3、虚函数

4、递归函数

举例说明如下

头文件中

#ifndef ICPP_HEADER_H
#define ICPP_HEADER_H
#include <iostream>
using namespace std;
class Str {int x;int y = 3;
public:void fun() {cout << "yes pf" << endl;}
};#endif //ICPP_HEADER_H

main文件中

#include "header.h"
#include <iostream>
using namespace std;int main() {int a = 0;int c = a + 7;Str str;str.fun();std::cout << "Hello, World!" << std::endl;return 0;
}

另外一个源文件中这样写

#include "header.h"
#include <iostream>

编译成功

但是如果,头文件中,类内声明,类外定义,就会报错。

#ifndef ICPP_HEADER_H
#define ICPP_HEADER_H#include <iostream>
using namespace std;
class Str {int x;int y = 3;
public:void fun();
};void Str::fun() {cout << "yes pf" << endl;}
#endif //ICPP_HEADER_H

报错信息如下:

/mnt/e/iCode/icpp/header.h:17: multiple definition of `Str::fun()'; CMakeFiles/icpp.dir/main.cpp.o:/mnt/e/iCode/icpp/header.h:17: first defined here
collect2: error: ld returned 1 exit status

问题分析

关于函数的声明和定义可以写在头文件之中,也可以写在源文件之中,但如果不加inline,那么写在头文件之中被多个源文件 include 那么就会导致符号重定义冲突,单个源文件引入却不会。

  1. 如果仅有一个头文件,一个文件使用头文件中的类的外部定义,不会出现问题;
  2. 类内定义和实现函数,不论有多少外部使用这个头文件的源文件都不会报错;
  3. 多文件使用头文件时,类内声明,类外定义,将类外的定义声明成内联函数,使用inline关键字不会报错;
  4. 掌握inline关键字的使用方法;

4. 分析下面几种写法

回答以下几个问题:

  1. 这个使用方法using my_int = int

  2. 类外声明的使用的使用方法,最好使用下面这种写法

  3. inline auto Str::fun2()->my_int {{cout<<"my_int"<<endl;}
    }
    

    举例如下:

//
// Created by pfw20 on 2024/3/31.
//#ifndef ICPP_HEADER_H
#define ICPP_HEADER_H#include <iostream>
using namespace std;
class Str {using my_int = int;my_int m;int x;int y = 3;
public:void fun();my_int fun1();my_int fun2();
};inline Str::my_int Str::fun1() {{cout<<"my_int"<<endl;}
}
// 简化上述的代码另外一种写法
inline auto Str::fun2()->my_int {{cout<<"my_int"<<endl;}
}inline int Add(int x, int y) {return x + y;
}
inline void Str::fun() {cout << "yes pf" << endl;}
#endif //ICPP_HEADER_H

待说明:

\#include<iostream>\#include<limits>struct A{// char a = 'a';int c =10;};int main(){int x =10;char y = 'a';std::cout<<std::numeric_limits<int>::min()<<std::endl;std::cout<<sizeof(A)<<std::endl;std::cout<<alignof(int) <<std::endl;}

5. this指针,指向当前对象

在类的内部会有一个this指针,类型为class* this 隐藏指针,this 是一个常量,指针不能修改,指针指向的内容是可以修改。

修改类的成员所以可以使用this->成员,访问类内的成员,

用处:

  1. 使用this可以防止函数中的参数和类中的成员混淆
  2. 基于const的成员函数重载

class Str{void fun(int x){}
// 基于const的成员函数重载void fun(int x) const{ // this 本身不能修改,可以修改指向的内容,加上const之后,指向的内容也是不能修改的。}int x;
};
  1. & 基于引用的重载(不作重点记录)

这个和基于const的重载不能混淆使用。仅仅使用const或者仅仅使用引用

  1. 多个相同的变量出现在类的内部和全局中,使用类内部的可以使用this指针,全局的使用::即可

静态成员函数

所有的对象共享这个成员函数,每一个对象有自己的对象成员,不会出现交叉

静态成员就没有this指针,使用这个成员可以使用;类的操作域进行访问这个静态成员。

这个就可以将全局的常量定义为static的格式。

用处:

  1. 描述和类相关参数,和对象无关
  2. 静态成员函数可以返回静态数据成员;静态成员函数操作静态成员

单例模式

class Str{static auto& size(){static Str x;return x;}}

6. 报错原因分析

为什么直接报错:/mnt/e/iCode/icpp/main.cpp:18: undefined reference to Str1::x’`

#include <iostream>
class Str1{
public:static int x;int y;};
int main(){std::cout<<Str1::x<<std::endl;
}

修改如下运行成功

#include <iostream>
class Str1{
public:inline static int x;int y;
};
int main(){std::cout<<Str1::x<<std::endl;// 输出0
}

C++特性封装:举例子洗衣机的电路板

7. C++特殊的成员函数

构造函数

代理构造函数

构造函数是可以重载的

C++11的代理构造函数,代理构造函数先执行

代理构造函数如下:(基本不使用,仅仅了解即可)

\#include <iostream>
class Strp{
public:Strp():Strp(10){std::cout<<"here1"<<std::endl;}Strp(int input){x = input;std::cout<<"here2"<<std::endl;}
private:int x;
};int main(){Strp strp1;
}

构造函数初始化(重要)

初始化列表,不使用缺省初始化

区分数据成员的初始化和赋值

  • 在构造的时候通过列表初始化完成,提升系统的性能
#include <iostream>
#include <string>class Strp {
public:Strp(const std::string &val) : x(val), y(0) {std::cout<<x<<std::endl;}private:std::string x;int y;
};int main() {Strp strp1("pf");
}
  • 类中包含引用的成员,此时必须使用列表进行初始化
#include <iostream>
#include <string>class Strp {
public:Strp(const std::string &val,int& ref_i): x(val), y(0),ref(ref_i) {std::cout<<x<<std::endl;ref =2;}private:std::string x;int y;int& ref;
};int main() {int val;Strp strp1("pf",val);
}
  • 元素的初始化顺序与其声明的顺序有关,与初始化列表中的顺序无关;

    要求在初始化化列表时,顺序要一致,这里的一致就是先声明的先进行初始化,否则会包warnning

  • 使用初始化列表覆盖类的内部的初始化信息

缺省的构造函数

  • 不提供实参的构造函数

  • 如果没有定义构造函数,编译器会提供一个缺省的构造函数,目的和C语言兼容,如果写一个就不会合成,如果类的成员中有引用成员,引用必须显示初始化。

  • 缺省的构造函数会缺省构造函数进行缺省初始化。

  • 调用缺省的构造函数避免(most vexing parse)

  • 使用default定义,和内部的缺省的构造函数是一样的

举例子说明如下:

报错:

#include <iostream>
#include <string>class Strp {
public:
//    Strp() = default;Strp(const std::string &input) : x(input) {}std::string x;
};int main() {
Strp s;
}

No matching constructor for initialization of ‘Strp’

#include <iostream>
#include <string>class Strp {
public:Strp() = default;Strp(const std::string &input) : x(input) {}std::string x;
};int main() {
Strp s;
}

不再进行报错

或者下面这样写,也不会报错

#include <iostream>
#include <string>class Strp {
public:Strp(){}Strp(const std::string &input) : x(input) {}std::string x;
};int main() {
Strp s;
}

单一的参数构造函数

  • 可以将其看成是一种类型转换

  • 可以使用explicit关键字避免求值过程中的隐式转换

    #include <iostream>
    #include <string>class Myclass {
    public:
    //    explicit Myclass(const int& input): x(input) {}int x;
    };int main() {Myclass my(3);// 直接参数列表进行初始化Myclass m1 = 3;// // 拷贝初始化,涉及到类型的隐式转换,避免隐式转换使用explicit进行标注Myclass m2{3};Myclass m3(Myclass(3));}
    

拷贝的构造函数(重要)

原有的对象来构造一个新的构造函数

不希望改变值,不能使用值传递,原因是会进行嵌套,死循环

  • 拷贝构造函数的经典写法
  • 如果没有显示提供拷贝构造函数,编译器会自动生成一个,对每一个数据成员调用拷贝构造
#include <iostream>
#include <string>class Myclass {
public:
//    explicit // 全部考虑是引用传递,引用是对值的绑定
// 单一参数的构造函数Myclass(const int &input) : x(input) {}// 缺省的构造函数Myclass() = default;// 拷贝的构造函数的经典写法,为什么是const,为什么是引用
//    Myclass(const Myclass&) = default;Myclass(const Myclass &m) : x(m.x) {// 这个也可以使用default}int x = 4;
};int main() {Myclass my(3);// 直接参数列表进行初始化Myclass m1 = 3;// // 拷贝初始化,涉及到类型的隐式转换,避免隐式转换使用explicit进行标注Myclass m2{3};Myclass m3(Myclass(3));}

移动构造函数(待更新)

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

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

相关文章

BOM系统:贯穿制造全程的管理利器

在制造行业中&#xff0c;BOM系统的应用已经成为提高生产效率、降低成本和确保产品质量的关键因素。BOM系统作为产品结构和物料清单的管理工具&#xff0c;为制造企业提供了全面的控制和协同能力。 1.产品设计与开发&#xff1a;在产品设计阶段&#xff0c;BOM系统为工程师提供…

基于自动编码器的预训练模型方法模型预训练方法RetroMAE和RetroMAE-2

文章目录 RetroMAERetroMAE详情编码解码增强解码 RetroMAE-2RetroMAE-2详情编码[CLS]解码OT解码和训练目标向量表征 总结参考资料 RetroMAE RetroMAE 出自论文《RetroMAE: Pre-Training Retrieval-oriented Language Models Via Masked Auto-Encoder》&#xff0c;是一种针对于…

ES-7.12-官方文档阅读-ILM-Automate rollover

教程&#xff1a;使用ILM自动化滚动创建index 当你持续将带有时间戳的文档index到Elasticsearch当中时&#xff0c;通常会使用数据流&#xff08;data streams&#xff09;以便可以定义滚到到新索引。这是你能够实施一个hot-warm-cold架构来满足你的性能要强&#xff0c;控制随…

OpenHarmony实战:RK3568 开发板镜像烧录指南

前言 烧录开发板是每个开发者的必修课&#xff0c;每次对系统的修改务必进行烧录测试&#xff0c;确保修改正确和不会引入新问题。 本文基于 Windows10&#xff0c;以 RK3568 开发板为例&#xff0c;指导如何烧录 OpenHarmony 镜像&#xff0c;镜像也叫固件。Hihoop&#xff…

Oracle利用BBED恢复崩溃实例(ORA-01092,ORA-00704,ORA-01578)

BBED修复数据损坏引起的数据库崩溃&#xff08;ORA-01092,ORA-00704,ORA-01578&#xff09;(2021年某苏州国企的案例&#xff09; 1.Symptom 用户一个边缘系统出现数据文件损坏&#xff0c;且没有备份&#xff0c;数据库无法启动 报错如下&#xff0c;发现是oracle bootstra…

【Vue3进阶】- 第2学堂小商城实战课程前言

该教程为进阶教程&#xff0c;如果你还不了解Vue3的基础知识&#xff0c;可以先前往Vue3基础教程&#xff0c;从入门到实战。 学习时遇到的任何疑问都欢迎在相应课文页面下方的问答区进行提问哦 我能学到什么&#xff1f; 编程写法千千万&#xff0c;实现需求是第一。 教程中…

Docker容器、Serverless与微服务:腾讯云云原生架构技术实践案例集解析

前言 随着云原生技术的飞速发展&#xff0c;容器化和函数计算正成为企业和开发者关注的焦点。在这一潮流中&#xff0c;腾讯云凭借其卓越的技术实力和深厚的行业积累&#xff0c;发布了《2023腾讯云容器和函数计算技术实践精选集》&#xff0c;为我们提供了一份深入探索云原生…

C# 异步问答集

问&#xff1a;调用方法(callingmethod):该方法调用异步方法&#xff0c;然后在异步方法执行其任务的时候继续执行(可能在相同的线程上&#xff0c;也可能在不同的线程上)。为什么会在不同的线程上&#xff1f; 答&#xff1a;在调用异步方法后&#xff0c;调用方法不会立即…

CAS(Compare And Swap)

目录 CAS概念 乐观锁与悲观锁 ABA问题 Unsafe类 ​编辑 原子类 基本类型原子类 原子引用类 原子数组 原子更新器类 原子累加器 CAS概念 CAS是Compare And Swap的缩写&#xff0c;中文翻译成&#xff1a;比较并交换&#xff0c;实现无锁并发时常用到的一种技术。它一…

3.Labview字符串与路径精讲(下) — 字符串及路径的用法汇总

本章讲解labview中的字符串和路径具体实践用例&#xff0c;从前面板字符串属性到后面板字符串函数应用做出详细概述&#xff0c;通过本文的学习希望大家了解到字符串及路径在labview编程中的重要地位。 本系列文章为labview 从基础到强化到精通的学习文章&#xff0c;大家可以随…

奥比中光深度相机(二):PyQt5实现打开深度摄像头功能

文章目录 奥比中光深度相机&#xff08;二&#xff09;&#xff1a;PyQt5实现打开深度摄像头功能官方给出的调用深度相机源码环境精炼 UI界面设计逻辑代码构建槽函数连接提取视频流在界面中显示深度视频流注意关闭相机 总体代码效果演示运行main.py代码选择相机打开摄像头关闭摄…

Kubernetes:Kubernetes应用包管理Helm

1. Helm介绍 Helm用于对需要在Kubernetes上部署的复杂应用进行定义、安装和更新。Helm以Chart的方式对应用软件进行描述&#xff0c;可以方便地创建、版本化、共享和发布复杂的应用软件。它是Kubernetes的软件包管理工具。包管理器类似Centos中使用的yum或者Python中的pip一样…

HarmonyOS实战开发-如何实现一个简单的健康生活应用(上)

介绍 本篇Codelab介绍了如何实现一个简单的健康生活应用&#xff0c;主要功能包括&#xff1a; 用户可以创建最多6个健康生活任务&#xff08;早起&#xff0c;喝水&#xff0c;吃苹果&#xff0c;每日微笑&#xff0c;刷牙&#xff0c;早睡&#xff09;&#xff0c;并设置任…

nodejs 中 yarn的安装和使用

Yarn是一个快速、可靠、易于使用的包管理工具,它是Facebook、Google、Tencent等公司使用的默认JavaScript包管理工具。Yarn可以帮助开发者在项目中管理依赖,确保不同环境之间的依赖一致性,并且加速依赖的下载和安装。 安装Yarn Yarn支持多种操作系统,包括macOS、Linux和W…

BabySQL【2019极客大挑战】

知识点&#xff1a; 功能分析 登录界面一般是 where username and password 可以从username出手&#xff0c;注释掉and语句单引号闭合绕过 通过测试和报错信息发现是一个单引号读取输入可以单引号闭合绕过关键字过滤 or and 过滤 || &&替换双写绕过select from wher…

【leetcode】力扣简单题两数之和

题目 思路 代码实现 #include<iostream> #include<unordered_map>using namespace std;class Solution { public:vector<int> TwoNumber(const vector<int>& nums, int target){vector<int> number_vector;unordered_map<int, int> …

【Linux】常见命令

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 常用命令 1. ls2. pwd3. cd4. touch5. cat6. mkdir7. rm8. cp9. mv10. tail11. vim12.…

TCP粘包是怎么回事,如何处理?

还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#xff0c;webgl&#xff0c;ech…

java-网络编程-(socket)-聊天室的编写 -01

socket 是java中的一插口,要实现网络通信的话,需要连接插口和插口,而数据的传输使用了流的思想,读数据操作运用了输入流,而写数据运用了输出流, 聊天对话的实现 一个类作为服务端对象,用于接受客户端写出的输出流, 一个类作为客户端对象,用于输到的服务端的进行读取的输入流…

css隐藏溢出隐藏的滚动条

msOverflowStyle: none: 这个属性用于在 Internet Explorer 浏览器中定义滚动条的样式。将其设置为 none 可以隐藏滚动条。 scrollbarWidth: none: 这个属性用于定义滚动条的宽度。将其设置为 none 可以隐藏滚动条。这个属性在一些新的浏览器中被支持&#xff0c;如 Firefox。…