深蓝学院C++基础与深度解析笔记 第 11 章 类

这篇具有很好参考价值的文章主要介绍了深蓝学院C++基础与深度解析笔记 第 11 章 类。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

深蓝学院C++基础与深度解析笔记 第 11 章 类

1. 结构体与对象聚合
● 结构体 对基本数据结构进行扩展,将多个对象放置在一起视为一个整体

– 结构体的声明与定义(注意定义后面要跟分号来表示结束)
– 仅有声明的结构体是不完全类型( incomplete type )
– 结构体(以及类)的一处定义原则:翻译单元级别

● 数据成员(数据域)的声明与初始化

– ( C++11 )数据成员可以使用 decltype 来声明其类型,但不能使用 auto(除静态)
– 数据成员声明时可以引入 const 、引用等限定
– 数据成员会在构造类对象时定义
– ( C++11 )类内成员初始化
– 聚合初始化:从初始化列表到指派初始化器
#include <iostream>
struct Str 
{
     int x;
     int y;
}

int main()
{
  Str m_str;
  m str.x = 3;
  std::cout < m str.x < std::endl; 
}

有声明即可定义指针,结构体内可以使用decltype(),不可以使用auto;
● mutable 限定符,只能在结构体内限定定义
● 静态数据成员 多个对象之间共享的数据成员

– 定义方式的衍化

深蓝学院C++基础与深度解析笔记 第 11 章 类,深蓝学院C++笔记,c++,笔记,java
● C++98 :类外定义, const 静态成员的类内初始化
● C++17 :内联静态成员的初始化

– 可以使用 auto 推导类型

● 静态数据成员的访问

– “.” 与“ ->” 操作符
– “::” 操作符

● 在类的内部声明相同类型的静态数据成员

2. 成员函数(方法)

C语言不可以在结构体中定义函数;C++可以在结构体中定义函数,作为其成员的一部分:对内操作数据成员,对外提供调用接口:

– 在结构体中将数据与相关的成员函数组合在一起将形成类,是 C++ 在 C 基础上引入的概念
– 关键字 class, struct在此类似于public:
– 类可视为一种抽象数据类型,通过相应的接口(成员函数)进行交互
– 类本身形成域,称为类域 

● 成员函数的声明与定义:

– 类内定义(隐式内联)
– 类内声明 + 类外定义, 类外显示内联:inline
– 类与编译期的两遍处理:但是只能处理内置类型后置,自定义类型还是需要桉顺序使用
– 成员函数与尾随返回类型( trail returning type )

● 成员函数与 this 指针: str *const this

– 使用 this 指针引用当前对象
– 基于 const 的成员函数重载,this本身不能修改,但是this->x可以

● 成员函数的名称查找与隐藏关系: 先找最小范围的作用域,在递归的寻找外一层的作用域

– 函数内部(包括形参名称)隐藏函数外部
– 类内部名称隐藏类外部
– 使用 this 或域操作符引入依赖型名称查找

ps: 类名::变量/函数即为该类下的变量/函数, :: 变量/函数:中省略::前的作用域范围即为全局的变量/作用域
● 静态成员函数:被所有对象共享

– 在静态成员函数中返回静态数据成员

● 成员函数基于引用限定符的重载( C++11 )

3. 访问限定符与友元
访问限定符与友元
● 使用 public/private/protected 限定类成员的访问权限

– 限定目标 : 访问权限的引入使得可以对抽象数据类型进行封装
– 类与结构体缺省访问权限的区别: C++默认:private, C 默认类似于public

● 使用友元打破访问权限限制 关键字 —— friend

– 声明某个类或某个函数是当前类的友元 慎用! —— 改变了【封装】  特性
– 在类内首次声明友元类或友元函数:可以先声明freined ,再定义;声明friend和声明函数是两个概念
  ● 注意使用限定名称引入友元并非友元类(友元函数)的声明: 假如使用了全局限定::则需要提前声明或定义函数
#include <iostream>
#include <vector>

class Str2;
class str 
{
    friend Str2;  // str2可以访问str的私有和保护类型的数据和函数 ,单向的   
public:
    inline static int x; 
private:
    int y;
};

class Str2 
{
    void fun() 
    {
        std::cout<<Str::x<< std::endl; 
    }
}; 
– 友元函数的类内外定义与类内定义

隐藏友元( hidden friend ):常规名称查找无法找到,在类内定义

● 好处:减轻编译器负担,防止误用
● 改变隐藏友元的缺省行为:在类外声明或定义函数

4. 构造、析构与复制成员函数

● 构造函数: 构造对象时调用的函数,无返回

– 名称与类名相同,无返回值,可以包含多个版本(可重载)
– 代理构造函数( C++11 ):使用别的函数完成构造,然后再执行本构造函数的内容

代理构造:
深蓝学院C++基础与深度解析笔记 第 11 章 类,深蓝学院C++笔记,c++,笔记,java
● 初始化列表: 区分数据成员的初始化与赋值,尽量和初始化顺序一致
深蓝学院C++基础与深度解析笔记 第 11 章 类,深蓝学院C++笔记,c++,笔记,java

– 通常情况下可以提升系统性能
– 一些情况下必须使用初始化列表(如类中包含引用成员)
– 注意元素的初始化顺序与其声明顺序相关,与初始化列表中的顺序无关(初始化列表可能顺序不一致,但是声明顺序是固定的,为了满足先构造的后销毁的原则)
– 使用初始化列表覆盖类内成员初始化的行为

先构造的后销毁,后构造的对象先销毁!
● 缺省构造函数: 不需要提供实际参数就可以调用的构造函数

– 如果类中没有提供任何构造函数,那么在条件允许的情况下,编译器会自动合成一个缺省构造函数
– 合成的缺省构造函数会使用缺省初始化来初始化其数据成员
– 调用缺省构造函数时避免 most vexing parse
classname m();      //会把m认为是函数而不是对象

使用 = default 关键字定义缺省构造函数,只有编译器能合成的函数它才会去合成。

● 单一参数构造函数

– 可以视为一种类型转换函数
– 可以使用 explicit 关键字避免求值过程中的隐式转换

● 拷贝构造函数: 接收一个当前类对象的构造函数

– 会在涉及到拷贝初始化的场景被调用,比如:参数传递。因此要注意拷贝构造函数的形参类型
– 如果未显式提供,那么编译器会自动合成一个,合成的版本会依次对每个数据成员调用拷贝构造

● 移动构造函数 (C++11) :
将旧的对象转移给新对象后,旧的对象自动销毁。接收一个当前类右值引用对象的构造函数,进一步提升系统性能。

– 可以从输入对象中“  偷窃”  资源,只要确保传入对象处于合法状态即可
– 当某些特殊成员函数(如拷贝构造)未定义时,编译器可以合成一个,有移动调移动,没有移动调拷贝 (C++17)
– 通常声明为不可抛出异常的函数: noexcept,一旦抛出就会崩溃
– 注意右值引用对象用做表达式时是左值! 

PS:&& 代表右值引用

语义移动:
在C++中,移动语义是一种优化技术,用于在对象之间转移资源的所有权,而不是进行复制。 当你移动一个对象时,源对象的资源所有权转移到目标对象,源对象不再拥有该资源。

移动操作通常使用移动构造函数和移动赋值运算符来实现。这些特殊的成员函数允许你有效地将资源(如堆上的内存、文件句柄等)从一个对象转移到另一个对象,而无需进行代价昂贵的复制操作。

在进行移动操作时,原始对象的内存空间仍然存在,但它的状态可能会变为有效但不确定的状态。 是因为移动操作不对原始对象进行显式的清理或重置,这意味着你不能再对原始对象进行任何有意义的操作,因为它的资源已被移动到其他对象。对于移动后的原始对象,你可以选择销毁它或重新赋值为其他有效值。(为了避免误用移动操作导致不确定状态,建议清理!)

移动操作的主要好处是避免了不必要的复制开销,特别是在涉及大型对象或资源密集型对象时。通过移动对象,可以更高效地管理资源并提高程序的性能。

需要注意的是,只有具有可移动语义的对象才能被移动。这包括具有移动构造函数和移动赋值运算符的类,或者具有可移动成员的类(如std::unique_ptr、std::vector等)。

总结起来,移动操作将资源的所有权从一个对象转移到另一个对象,原始对象进入有效但不确定的状态,而移动后的对象获得资源的所有权。移动操作的主要目的是避免不必要的复制并提高程序性能。

● 拷贝赋值与移动赋值函数( operator = )

Str m;        //缺省构造函数  无参
Str m2 = m;   //拷贝赋值
Str m3(m2);   //移动构造函数
m3 = m;       //赋值运算符,会被翻译成 m3.opreator = (m);

拷贝赋值返回值是:类名&

– 注意赋值函数不能使用初始化列表
– 通常来说返回当前类型的引用
– 注意处理给自身赋值的情况
– 在一些情况下编译器会自动合成

● 析构函数

– 函数名:“ ” ~ 加当前类型,无参数,无返回值
– 用于销毁对象以及扫尾工作,执行完最后一句才会跳出执行内存回收。
– 注意内存回收是在调用完析构函数时才进行
– 除非显式声明,否则编译器会自动合成一个,其内部逻辑为平凡的
– 析构函数通常不能抛出异常

● 通常来说,一个类:

– 如果需要定义析构函数,那么也需要定义拷贝构造与拷贝赋值函数(显式地)
– 如果需要定义拷贝构造函数,那么也需要定义拷贝赋值函数
– 如果需要定义拷贝构造(赋值)函数,那么也要考虑定义移动构造(赋值)函数

没有定义在使用时就会造成二次释放或者多次释放
ps:

1. Rule of Three (三法则):
如果需要定义析构函数、拷贝构造函数或拷贝赋值函数中的任何一个,就需要显式定义这三个函数。

这个原则确保了资源管理的正确性和一致性。

2. Rule of Five (五法则):
在C++11及更高版本中,如果需要定义拷贝构造函数或拷贝赋值函数,就需要同时定义析构函数、拷贝构造函数和拷贝赋值函数,并且还要考虑定义移动构造函数和移动赋值函数。

这个原则兼容了移动语义,提高了对象的性能和效率。

请注意,这些名称是广为接受的通用术语,用于描述C++编程中的最佳实践。
● 示例:包含指针的类:

● default 关键字
– 只对特殊成员函数有效

● delete 关键字
=delete 表示禁用该函数

– 对所有函数都有效
– 注意其与未声明的区别
– 注意不要为移动构造(移动赋值)函数引入 delete 限定符

深蓝学院C++基础与深度解析笔记 第 11 章 类,深蓝学院C++笔记,c++,笔记,java

● 如果只需要拷贝行为,那么引入拷贝构造即可
● 如果不需要拷贝行为,那么将拷贝构造声明为 delete 函数即可
● 注意 delete 移动构造(移动赋值)对 C++17 的新影响

如果一个类有用户自定义的拷贝赋值运算符或拷贝构造函数,或者有用户自定义的析构函数,那么该类的相关默认函数的隐式定义会被弃用,并且在未来的C++版本中可能会被删除,需要显式定义相关函数来替代。

5. 字面值类,成员指针与 bind 交互

● 字面值类:可以构造编译期常量的类型

– 其数据成员需要是字面值类型
– 提供 constexpr / consteval 构造函数 (小心使用 consteval )
– 平凡的析构函数(没有自定义行为的析构函数)
– 提供 constexpr / consteval 成员函数 (小心使用 consteval )
– 注意:从 C++14constexpr / consteval 成员函数非 const 成员函数

constexprconsteval区别:

constexprconsteval是C++中的两个关键字,用于指定编译时常量表达式和编译时求值函数。

  1. constexpr

    • constexpr是C++11引入的关键字,用于声明一个编译时常量表达式。它可以应用于变量、函数、构造函数等。
    • constexpr声明的变量必须在编译时求值并产生常量结果,可以用于编译时常量的计算和编译时优化。
    • constexpr函数是在编译时进行求值的函数,它的参数和返回值必须是可编译时求值的表达式,函数体内只能包含可编译时求值的语句。
    • 在C++14之前,constexpr函数只能包含一些简单的计算和控制流程,而在C++14及以后的版本中,constexpr函数可以包含更复杂的逻辑。
  2. consteval

    • constevalC++20引入的关键字,用于声明一个编译时求值函数,要求在编译时执行。
    • consteval函数是在编译时强制执行的函数,它的参数和返回值必须是可编译时求值的表达式,函数体内只能包含可编译时求值的语句。
    • constexpr函数不同,consteval函数在编译时强制要求函数的调用结果能在编译期间确定,否则会引发编译错误。
    • consteval函数适用于需要在编译时执行的严格要求,可以用于生成更高效的代码,但使用场景相对较少。

总结:
constexpr用于声明编译时常量表达式和函数,而consteval用于声明在编译时强制求值的函数。它们都提供了在编译期间进行求值和优化的能力,但consteval更加严格,要求函数在编译时一定能求值,否则会导致编译错误。

● 成员指针

– 数据成员指针类型示例: int A::*;  即使A中没有任何东西
– 成员函数指针类型示例: int (A::*)(double);
– 成员指针对象赋值: auto ptr = &A::x;
   ● 注意域操作符子表达式不能加小括号(否则 A::x 一定要有意义,例如静态)
   – 成员指针的使用:
        ● 对象 .* 成员指针
        ● 对象指针 ->* 成员指针

无法加减,会被认为不是同一类型的,下式报错:
深蓝学院C++基础与深度解析笔记 第 11 章 类,深蓝学院C++笔记,c++,笔记,java

● bind 交互: 需要引入类的对象文章来源地址https://www.toymoban.com/news/detail-544337.html

– 使用 bind + 成员指针构造可调用对象
– 注意这种方法也可以基于数据成员指针构造可调用对象

到了这里,关于深蓝学院C++基础与深度解析笔记 第 11 章 类的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【深蓝学院】移动机器人运动规划--第2章 基于搜索的路径规划--笔记

    Configuration Space等概念 机器人配置: 指机器人位置和所有点的表示。 DOF: 指用于表示机器人配置所需的最小的实数坐标的数量n。 C-space: 包含机器人n维所有配置的空间。 在C-space中机器人的pose是一个点。 机器人在C-space中被表示为一个点,pose包含为R,t 空间中的障碍物也需要映

    2024年01月22日
    浏览(47)
  • 深度解析C++异常处理机制:分类、处理方式、常见错误及11新增功能

    异常是程序在运行过程中出现非正常情况的处理机制。当出现异常时程序会停止运行并调用异常处理程序。 异常可以分为内置异常和自定义异常 2.1 内置异常 C++ 标准库提供了许多预定义的异常类,称为内置异常,包括以下几种: std::exception :所有标准异常类的基类。 std::

    2024年01月18日
    浏览(43)
  • Java基础教程——Java封装的深度解析

    封装是面向对象编程中的一项关键概念,它是一种将对象的状态和行为封装在一起的机制,通过访问控制来限制对对象内部细节的直接访问。Java作为一门面向对象的编程语言,强烈支持封装,通过 private 、 protected 、 public 等,提供了丰富的访问修饰符来实现封装。 封

    2024年02月01日
    浏览(37)
  • C++基础与深度解析01——函数基本组成+函数传参的三种方法

    请安装Visual Studio 并学习基本的新建项目、新建CPP文件以及运行代码。 函数功能:打印“Hello World” 1.函数构成 输入参数列表+函数名+返回类型+函数主体 如下图所示,但是main函数稍有特殊,其为cpp 现举一个简单函数的例子,z= 2x-3y+3,其中xy均为浮点型小数,取函数名为CalBi

    2024年02月16日
    浏览(46)
  • 【深度学习】日常笔记11

    在torch中 微分相当于高数里的求导。 在高等数学中,求导是计算一个函数在某一点处的变化率,表示该点附近的函数值对自变量的微小变化的响应。而在 Torch 中,微分操作也是计算张量函数在某一点处的变化率,即计算函数对输入张量的偏导数。 Torch 提供了丰富的自动微分

    2024年02月17日
    浏览(36)
  • 【动手学习深度学习--逐行代码解析合集】11实战Kaggle比赛:预测房价

    视频链接:动手学习深度学习–实战Kaggle比赛:预测房价 课程主页:https://courses.d2l.ai/zh-v2/ 教材:https://zh-v2.d2l.ai/ 1、下载和缓存数据集 首先,我们建立字典DATA_HUB, 它可以将数据集名称的字符串映射到数据集相关的二元组上, 这个二元组包含数据集的url和验证文件完整性

    2024年02月13日
    浏览(39)
  • 【C++】C++11 ~ 包装器解析

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年02月01日
    浏览(34)
  • 【C++】引用(上)【深度全面解析】

    🌹作者:云小逸 📝个人主页:云小逸的主页 📝Github:云小逸的Github 🤟motto:要敢于一个人默默的面对自己, 强大自己才是核心 。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天

    2023年04月14日
    浏览(34)
  • Pysyft学习笔记,11安全深度学习分类

    数据是机器学习的推动力 创建和收集数据的组织能够构建和训练自己的机器学习模型。这使他们能够向外部组织提供此类模型即服务(MLaaS)的使用。这对于某些组织很有用——他们无法自行创建这些模型,但仍希望使用此模型对自己的数据进行预测。 但是,托管在云中的模

    2024年04月26日
    浏览(34)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包