C++学习笔记04-补充知识点(问题-解答自查版)

news2024/11/15 15:33:12

前言

以下问题以Q&A形式记录,基本上都是笔者在初学一轮后,掌握不牢或者频繁忘记的点

Q&A的形式有助于学习过程中时刻关注自己的输入与输出关系,也适合做查漏补缺和复盘。

本文对读者可以用作自查,答案在后面,需要时自行对照。


问题集

Q1:C++中是否有相关设计,类似实现“接口”的功能?

Q2:当我们在Class A类中定义了一个纯虚函数的时候,A类还可以被实例化吗?为什么?

Q3:我们如何合规地使用C++中的“接口”?

Q4:虚函数中 virtual 关键字对程序起到的实质性的作用?(注意区分虚继承)

Q5:override的书写,在函数多态中可有可无?

Q6:虚函数有哪些额外的开销?运行时成本?

Q8:release和debug版本的具体区别?

 Q9:C++中默认的隐式转换可以做几次?

Q10:explicit关键字是用来干什么的?

Q11:以下4句语句的 Animal a 对象,各自分配在堆还是栈上?

        在栈和堆上,各自作用域/生存周期有何不同?

 Q12:作用域内变量自动销毁的特性,若想利用,可以有什么好的实践?(看看即可)

Q13:对于unique_ptr,为什么不能通过以下语法实现复制?

Q14:对于智能指针,为什么不建议通过new对象获得指针,而是使用 std::make_xx<>  方法?

Q15:关于强制转换,C风格的方法和C++风格的方法有何不同?

Q16:static_cast、dynamic_cast、const_cast 分别最主要用在什么地方?

Q17:dynamic_cast 比 static_cast 慢,为什么?


参考解答

Q1:C++中是否有相关设计,类似实现“接口”的功能?

A1:纯虚函数(pure virtual function),与java和C#中的接口定义比较接近

        定义一个没有实现的函数,强制要求继承所属类的派生类去实现它。

        其格式是 virtual ... func() = 0;

class Animal{   
public:
    int age = 10;
    static const int sex = 1;

    virtual void speak() = 0;       // 声明纯虚函数
};

Q2:当我们在Class A类中定义了一个纯虚函数的时候,A类还可以被实例化吗?为什么?

A2:不可以,A类的纯虚函数被要求必须指定一个子类,去实现其接口。(重写这个当做“蓝图”的纯虚函数)

        以上文中的例子,

        Animal *a = new Animal;         // 是不合法的语法

        不能实例化含有纯虚函数的类对象的原因有以下几点:

  1. 接口不完整:含有纯虚函数的类定义了一个不完整的接口。这意味着基类本身并没有提供足够的实现细节来创建一个完整的对象。

  2. 强制实现:纯虚函数的存在是为了确保所有派生类都实现了这些函数。如果允许实例化含有纯虚函数的类,那么这种强制实现的约束就被破坏了。

Q3:我们如何合规地使用C++中的“接口”?

A3:谨慎地多重继承。实际上很多其他语言都有关键字interface,但是C++只有class

         主要的代码可以是:

class InterFace{  ... 内有一个纯虚函数 }
...
class 需要这个接口的类 :public Base, InterFace{  ... 之后在这里重写纯虚函数 }

Q4:虚函数中 virtual 关键字对程序起到的实质性的作用?(注意区分虚继承)

A4:告诉编译器:“Hey,为我的这个函数创造一个vftable吧”

        如果这个函数被重写且被子类对象调用了,就按照重写(虚函数指针所指)的函数执行。

Q5:override的书写,在函数多态中可有可无?

A5:雀食可以省略,但是还是建议养成好习惯,坚持写上去增加可读性

class Cat : public Animal{
    void speak() override {
        cout << "Cat-speak" << endl;
    }    
};

Q6:虚函数有哪些额外的开销?运行时成本?

A6:1)我们需要额外的内存来存储v表,以分配到正确的函数,这会在Base类中多一个 *vfptr 的指针

2)在调用时,我们需要遍历这个表,来确定要映射到哪个函数

一般来说开销不会特别大,所以尽管用

Q7:我们在VS上写一个 "HelloWorld" 的时候,这个"HelloWorld"默认格式是string吗?

A7:不是诶,是 const char [ ] 类型!

        在C++中,字符串字面量(如 `"Hello, World!"`)会被编译器识别为 const char[] 类型,但是当使用标准库中的输入输出流时,如`std::cout`,它会隐式地将const char*(即 const char[] 的指针类型)转换为 std::string

Q8:release和debug版本的具体区别?

A8:1)编译器优化力度有所区别   2)调试信息,debug版本通常更丰富一些

        3)再者,初始化的变量值可能不同:

                在debug版本下,有的未初始化变量可能是 0xcccccccc。

                在release版本下,为了考虑性能这个部分内容应该是0x212B421F这样的随机脏数据

         4)断言:Debug版本中,断言(assertions)通常是启用的,以在开发过程中捕获潜在的错误。而在Release版本中,断言可能被禁用,以避免影响程序性能。


 

Q9:C++中默认的隐式转换可以做几次?

        我们假设有以下情境:

        1)这里的 "Cherno" 是一个 char 数组

        2)程序中有 class Entity ,带构造函数,构造函数可以构造属性 string Name = 输入

A9:我们在调用 PrintEntity 函数的时候,编译器试图在进行两次隐式转换:

        即,char[] 到 std::string 再到 Entity

        但是隐式转换在C++中默认只能自动进行一次,所以这里产生了错误。

        解决方式:选择以下写法中的任意一种

实际上,在这里我们使用了一种 “隐式构造函数” ,也就是经过隐式转化的构造函数,可以简化代码但最好避免使用。

Q10:explicit关键字是用来干什么的?

A10:主要用在构造函数上,要求显式类型调用构造函数,也就是强制要求禁止使用隐式转换确保输入参数的类型安全

例如要使用构造这个Dog对象,则必须显式调用此构造函数

这个语法主要是影响这种表达:

Dog e = 22;     // 调用的是dog的有参构造函数,相当于 e.age = (int)22
                // 显然,这种方式会产生一次隐式转换, 
                // err:不存在从 "int" 转换到 "Dog" 的适当构造函数C/C++(415)

然而以下方式定义就不会有问题:

Dog e(22);  或者 Dog* e = new Dog(22);  原因是他们不会将构造函数的入参弄成 int(22)

根据 "Cherno" 是一个 char 数组,也要注意尽可能用 std::string 作为输入,而不要用默认


堆上数据和栈上数据的生存周期问题(重要)

Q11:以下4句语句的 Animal a 对象,各自分配在堆还是栈上?

        在栈和堆上,各自作用域/生存周期有何不同?

A11:

1) Animal a;分配在空间上,他的作用域是整个main函数,因此会打印 create

2) {Animal a;}分配在空间上,不过他的作用域是他所在的代码块,因此会打印 create+destory

   注意!这里 a 因为结束了代码块的执行,作用域一过,自动被释放!

3){ Animal a = Animal(); } 分配在空间上,作用域是他所在的代码块,打印 create+destory

4){Animal* a = new Animal();}分配在空间上,作用域是他所在的代码块,但会长期存在,打印 create

栈是一种会自动默认跟随生命周期管理的数据结构,但是堆不会。堆的特点就是只能手动申请和释放

虽然有些时候编译器会帮我们去保留一段时间,但是完全不建议这么做。

尤其是这种代码:

Q12:作用域内变量自动销毁的特性,若想利用,可以有什么好的实践?(看看即可)

A12:

注意:这些应用都只针对作用域!

1)作用域指针(ScopedPtr):大概意思是使用一个类,其对象含有一个private的 Entity *类型,有构造和析构

        当我们即使是使用new申请堆空间的时候,也可以利用析构函数,达到自动释放的效果。

        这就是智能指针(smart ptr,或是unique_ptr)做的最基本的事情!

2)Timer计时器对象:构造时创建,析构时输出打印。你只需要在函数开头,写一行代码,那么整个作用域会被计时

3)自动mutex:在作用域内锁住,出作用域时解锁

这里简单补充一点智能指针的知识:

1)unique_ptr,作用域指针:

        不允许被复制,不会计数,会自动销毁

        出作用域时会自动释放。不能被复制,也就不会导致有2个ptr指向同一块内存进而引发释放错误

格式:std::unique_ptr<类名> ptr = std::make_unique<类名>();

效果:最终不会得到一个没有引用的悬空指针 从而造成内存泄露

完整程序:


class Animal{   
public:
    Animal() {
        cout << "create" << endl;
    }

    ~Animal() {
        cout << "destroy" << endl;
    }
};

int main(){
    {
        std::unique_ptr<Animal> ptr = std::make_unique<Animal>();
    }
    while (1);
    return 0;
}

2)共享指针 shared_ptr

        允许被复制,会计数,会自动销毁

        shared ptr的工作方式是通过引用计数,可以跟踪计数有多少个引用。当计数=0时才删除。(有点文件系统里面 inode或者信号量 的意思)

因为shared ptr需要分配另一块内存,叫做控制块,用来存储引用计数

3)弱指针 weak_ptr

        允许被复制,不会计数,会自动销毁

Q13:对于unique_ptr,为什么不能通过以下语法实现复制?

        std::unique_ptr<Entity> ptr_new ptr;

A13:编译器会报错,因为 std::unique_ptr 没有拷贝构造函数。

Q14:对于智能指针,为什么不建议通过new对象获得指针,而是使用 std::make_xx<>  方法?

        在 unique_ptr 中,不直接调用new的原因是因为异常安全

        当使用 new 创建对象时,如果对象的构造函数抛出异常,而程序员忘记使用智能指针来管理这个对象,那么这个对象将不会被正确地删除,导致资源泄漏。std::make_xx<>() 方法在内部处理了这些异常情况,确保了即使构造函数失败,资源也会被正确释放。

       在shared_ptr中,std::make_xx<>() 主要是用于共享指针需要获得控制块变量++,以便计数。

        另外,std::make_xx<>() 提供了一致的创建智能指针的方式。增加可读性,避免维护困难。

Q15:关于强制转换,C风格的方法和C++风格的方法有何不同?

A15:

C风格的方法: int a = (int)c

C++风格的方法:

1)静态转换:用于非多态类型的转换,如基本数据类型,编译时而非运行时进行检查

        int a = 10;

        double b = static_cast<double>(a); // 将int转换为double

2)动态转换:用于处理多态性,只能在含有虚函数的类层次结构中使用

        class Base { virtual void dummy() {} }

        class Derived : public Base {};

        Base* basePtr = new Derived();

        Derived* derivedPtr = dynamic_cast <Derived*>(basePtr);

        if (derivedPtr) {

                // 转换成功

        }

3)const_cast

        使得不能改写的const类型数据变得可以修改:

        const int* a = new int(10);

        int* b = const_cast<int*>(a); // 移除const限定符

Q16:static_cast、dynamic_cast、const_cast 分别最主要用在什么地方?

A16:

  1. static_cast

    1. 可用于基本数据类型之间的转换,如将 int 转换为 char 或将 float 转换为 int

    2. 可用于类层次结构中的向上转型(从派生类向基类转换),因为这是安全的,编译器知道所有相关的信息

  2. dynamic_cast

    • 主要用于处理多态性,即在运行时确定对象的实际类型。
    • 只能用于包含虚函数的类的指针或引用类型的向下转型(从基类向派生类转换)。
    • 如果转换失败,指针类型的 dynamic_cast 返回 nullptr,引用类型的转换会抛出 std::bad_cast 异常。
  3. const_cast

    • 主要用来修改类型的 const 限定符。
    • 可以用来将 const 类型的指针或引用转换为非 const 类型,或者反之。
    • 转换不会改变对象本身是否是常量,只是改变指针或引用的 const 属性。
    • 示例代码:
      const int* constIntPtr = new int(5);
      int* modifiableIntPtr = const_cast<int*>(constIntPtr);
      *modifiableIntPtr = 10; // 现在可以修改值

Q17:dynamic_cast 比 static_cast 慢,为什么?

A17:因为它需要在运行时检查对象的实际类型

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

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

相关文章

go-kratos 学习笔记(1) 安装

简介&#xff1a; Kratos 一套轻量级 Go 微服务框架&#xff0c;包含大量微服务相关框架及工具。 使用步骤&#xff1a; 安装cli工具 go install github.com/go-kratos/kratos/cmd/kratos/v2latest 创建项目 通过 kratos 命令创建项目模板 # 国内拉取失败可使用gitee源 krat…

C:一些题目

1.分数求和 计算1/1-1/21/3-1/41/5 …… 1/99 - 1/100 的值 #include <stdio.h>int main(){double sum 0.0; // 使用 double 类型来存储结果&#xff0c;以处理可能的小数部分int sign 1; // 符号标志&#xff0c;初始为 1 表示正数for (int i 1; i < 100; i)…

PGSQL学习-基础表结构

1 访问数据库 创建好数据库后&#xff0c;你可以有三种方式访问数据库 运行PostgreSQL的交互式终端程序&#xff0c;它被称为psql&#xff0c; 它允许你交互地输入、编辑和执行SQL命令。 使用一种已有的图形化前端工具&#xff0c;比如pgAdmin或者带ODBC或JDBC支持的办公套件…

Centos7_Minimal安装Cannot find a valid baseurl for repo: base/7/x86_6

问题 运行yum报此问题 就是没网 解决方法 修改网络信息配置文件&#xff0c;打开配置文件&#xff0c;输入命令&#xff1a; vi /etc/sysconfig/network-scripts/ifcfg-网卡名字把ONBOOTno&#xff0c;改为ONBOOTyes 重启网卡 /etc/init.d/network restart 网路通了

opencv 按键开启连续截图,并加载提示图片

背景图小图 键盘监听使用的是pynput 库 保存图片时使用了年月日时分秒命名 原图&#xff1a; from pynput import keyboard import cv2 import time# 键盘监听 def on_press(key):global jieglobal guanif key.char a:jie Trueelif key.char d:jie Falseelif key.char…

【深度学习】LLaMA-Factory 大模型微调工具, 大模型GLM-4-9B Chat ,微调与部署 (2)

资料&#xff1a; https://github.com/hiyouga/LLaMA-Factory/blob/main/README_zh.md https://www.53ai.com/news/qianyanjishu/2015.html 代码拉取&#xff1a; git clone https://github.com/hiyouga/LLaMA-Factory.git cd LLaMA-Factorybuild镜像和执行镜像&#xff1a; …

如何借助生成式人工智能引领未来的科技狂潮

如何借助生成式人工智能引领未来的科技狂潮 1. 生成式AI的现状1.1 技术基础1.1.1 深度学习1.1.2 生成对抗网络&#xff08;GANs&#xff09;1.1.3 变分自编码器&#xff08;VAEs&#xff09; 1.2 主要应用1.2.1 语言模型1.2.2 图像生成1.2.3 音频与视频生成 2. 未来的发展趋势2…

2024/7/23 英语每日一段

As malware has improved and evolved, it has pushed defense software to require constant connection and more extensive control. That deeper access also introduces a far higher possibility that security software—and updates to that software—will crash the …

6.乳腺癌良性恶性预测(二分类、逻辑回归、PCA降维、SVD奇异值分解)

乳腺癌良性恶性预测 1. 特征工程1.1 特征筛选1.2 特征降维 PCA1.3 SVD奇异值分解 2. 代码2.1 逻辑回归、二分类问题2.2 特征降维 PCA2.3 SVD奇异值分解 1. 特征工程 专业上&#xff1a;30个人特征来自于临床一线专家&#xff0c;每个特征和都有医学内涵&#xff1b;数据上&…

SpringBoot启动命令过长

Error running DromaraApplication: Command line is too long. Shorten command line for DromaraApplication or also for Spring Boot default configuration?

探索LLM世界:新手小白的学习路线图

随着人工智能的发展&#xff0c;语言模型&#xff08;Language Models, LLM&#xff09;在自然语言处理&#xff08;NLP&#xff09;领域的应用越来越广泛。对于新手小白来说&#xff0c;学习LLM不仅能提升技术水平&#xff0c;还能为职业发展带来巨大的机遇。那么&#xff0c;…

matlab仿真 模拟调制(下)

&#xff08;内容源自详解MATLAB&#xff0f;SIMULINK 通信系统建模与仿真 刘学勇编著第五章内容&#xff0c;有兴趣的读者请阅读原书&#xff09; clear all ts0.001; t0:ts:10-ts; fs1/ts; dffs/length(t); msgrandi([-3 3],100,1); msg1msg*ones(1,fs/10); msg2reshape(ms…

opencv grabCut前景后景分割去除背景

参考&#xff1a; https://zhuanlan.zhihu.com/p/523954762 https://docs.opencv.org/3.4/d8/d83/tutorial_py_grabcut.html 环境本次&#xff1a; python 3.10 提取前景&#xff1a; 1、需要先把前景物体框出来 需要坐标信息&#xff0c;可以用windows自带的画图简单提取像素…

敏捷CSM认证:精通敏捷Scum估算方法,高效完成项目!

咱们做项目的时候可能都遇到过这种情况&#xff1a;项目一开始信心满满&#xff0c;觉得 deadline 稳了。结果呢&#xff1f;各种意外状况频出&#xff0c;时间好像怎么都不够用了&#xff0c;最后项目只能无奈延期&#xff0c;整个团队都像霜打的茄子。 说到底&#xff0c;还…

Elasticsearch:Golang ECS 日志记录 - zap

ECS 记录器是你最喜欢的日志库的格式化程序/编码器插件。它们可让你轻松地将日志格式化为与 ECS 兼容的 JSON。 编码器以 JSON 格式记录日志&#xff0c;并在可能的情况下依赖默认的 zapcore/json_encoder。它还处理 ECS 错误格式的错误字段记录。 默认情况下&#xff0c;会添…

集合的概念

目录 概述 1 集合定义 1.1 基本定义 1.2 元素和集合的关系表述 1.3 集合分类 1.4 集合描述 1.5 集合关系描述 2 集合的运算 2.1 集合关系的定义 2.2 集合的运算 概述 在高等数学中&#xff0c;集合是指由一些具有共同特征的对象组成的整体。这些对象可以是数字、字母…

最短路径 | 743. 网络延迟时间之 Dijkstra 算法和 Floyd 算法

目录 1 基于 Dijkstra 算法1.1 代码说明1.2 完整代码 2 基于 Floyd 算法2.1 代码说明2.2 完整代码 前言&#xff1a;我在做「399. 除法求值」时&#xff0c;看到了基于 Floyd 算法的解决方案&#xff0c;突然想起来自己还没有做过最短路径相关的题。因此找来了「743. 网络…

灰色关联分析【系统分析+综合评价】

系统分析&#xff1a; 判断哪个因素影响最大 基本思想&#xff1a;根据序列曲线几何形状的相似程度来判断其练习是否紧密 绘制统计图并进行分析 确定子序列和母序列 对变量进行预处理&#xff08;去量纲、缩小变量范围&#xff09; 熟练使用excel与其公式和固定&#xff08…

微服务安全——OAuth2详解、授权码模式、SpringAuthorizationServer实战、SSO单点登录、Gateway整合OAuth2

文章目录 Spring Authorization Server介绍OAuth2.0协议介绍角色OAuth2.0协议的运行流程应用场景授权模式详解客户端模式密码模式授权码模式简化模式token刷新模式 OAuth 2.1 协议介绍授权码模式PKCE扩展设备授权码模式拓展授权模式 OpenID Connect 1.0协议Spring Authorizatio…

C语言数据结构:基于EasyX的飞机订票系统,有前端界面

数据结构课程设计说明书 学 院、系&#xff1a; 软件学院 专 业&#xff1a; 软件工程 班 级&#xff1a; 学 生 姓 名&#xff1a; 范 学 号&#xff1a; 设 计 题 目&#xff1a; 飞机订票系统 起 迄 日 期: 2024年6月18日~ 20…