C++学习笔记03-对象和类(问题-解答自查版)

news2024/11/15 19:47:48

前言

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

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

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

--

问题集

Q1:这组程序中,两个static变量哪个是长期在内存的?

Q2:C++中,内部链接性和外部链接性有什么区别?

Q3:#pragma once 以及 #ifndef ... #define xx_H_ ... #endif 的作用?

Q4:结构体和class的区别?

Q5:拷贝构造函数是干什么用的?定义的固定格式?(入参?)

Q6:以下程序中哪些试图调用构造函数的方式是正确的?

 Q7:以下程序调用几次拷贝构造?

void callPerson(Person p){
    return ;
}
int main(){
    Person p1;
    callPerson(p1);
    return 1;
}

Q8:以下程序调用几次拷贝构造?(区别是返回类型是Person

Person callPerson(Person p){
    return p;
}

int main(){
    Person p1;
    callPerson(p1);
    return 1;
}

Q9:构造函数调用规则如下:

        如果用户定义有参构造函数,则不在提供默认无参构造,但是会提供默认拷贝构造

        如果用户定义拷贝构造函数,c++默认不会再提供其他构造函数;

问题:如果我 Person p1 = p2,这个时候除了会调用拷贝构造函数,还会调用其他构造函数吗?(假设有定义~)

Q10:浅拷贝和深拷贝的定义?编译器默认提供的拷贝构造函数是什么样子的?

Q11:浅拷贝的bug是什么?

Q12:深拷贝的具体操作?

Q13:这个构造函数的语法?

class Person
{
public:
    int age;
    string name;
    Person():age(10),name("default") {cout<<"gz"<<endl;}
    ...
}

Q14:this指针的用法之一是防止冲突,还有什么作用?

Q15:这个类内成员函数的语法?

Q16:const Person p; 这个p能否调用

Q17:想想链表中的有参构造会怎么做?如何优雅的写出来带默认初始值的构造函数?

Q18:C++中支不支持类中类?

Q19:友元中的friend可以这么用吗?

int main(){
    friend p = Person();
    return 0;
}

Q20:友元的两个比较常用的操作

Q21:类外定义函数?可以定义构造函数吗?

Q22:运算符重载的本质?

Q23:运算符重载的两种方式?类内重载&全局重载?为什么要学习全局重载?

Q24:这个重载<<的操作正确吗?为什么要返回 ostream& 类型?

// 类外定义<<重载
ostream& Person::operator<<(ostream &out, const Person &p2){

}


参考解答

Q1:这组程序中,两个static变量哪个是长期在内存的?

A1:都在,而且全局外的 int global 和这俩,都是长期在内存中的。即使不调用 funct1(),具体参考下表

Q2:C++中,内部链接性和外部链接性有什么区别?

A2:在C++中,链接性(Linkage)指的是变量、函数或模板等实体在不同编译单元(Translation Unit)之间的可见性和可用性。

1)外部链接性(External Linkage,如 int global )

        具有外部链接性的实体可以在多个编译单元中被定义和使用。(多个文件中共享编译)

        这些实体在编译后生成的可执行文件或库文件中具有全局唯一性。

        例如,如果你在一个编译单元中声明了一个具有外部链接性的全局变量或函数,然后在另一个编译单元中引用它,编译器会链接到同一个全局实体。

        通常,全局变量和函数默认具有外部链接性,除非它们被声明为static。

2)内部链接性(Internal Linkage,如 static int global

        具有内部链接性的实体仅在其定义的编译单元内部可见。(仅当前cpp)

        这意味着即使在其他编译单元中声明了相同名称的实体,它们也会被视为不同的实体。

        内部链接性可以通过在全局变量或函数前加上static关键字来实现,这会限制其作用域仅在定义它的编译单元内

        这有助于避免命名冲突,并可以用于实现编译单元内私有的全局变量或函数。

Q3:#pragma once 以及 #ifndef ... #define xx_H_ ... #endif

        这两套东西是用来做什么的?

A3:#pragma once#ifndef ... #define ... #endif 都是用来防止头文件被多次包含的机制

        1. #pragma once 是一种非标准的、但广泛支持的预处理指令,用于指示编译器只包含一次头文件。当编译器遇到 #pragma once 时,它会确保该文件在整个编译单元中只被包含一次。这种方式简单且有效,但因为它不是C/C++标准的一部分,所以可能在某些编译器上不被支持

        2. #ifndef ... #define ... #endif 是一种标准的防止头文件重复包含的方法,通过宏定义来实现。具体步骤如下:
           - `#ifndef` 检查是否已经定义了某个宏(通常是头文件的名称,后缀 `_H_` 或 `_H` 是一种常见习惯)。
           - `#define` 如果没有定义,则定义该宏。
           - `#endif` 结束条件编译块。  

   // example.h
   #ifndef EXAMPLE_H_  // 如果没有定义 EXAMPLE_H_
   #define EXAMPLE_H_    // 定义 EXAMPLE_H_

   // 头文件内容

   #endif // EXAMPLE_H_

        第二种方式是标准的,可以在所有支持C/C++的编译器上工作。而 `#pragma once` 虽然在大多数现代编译器上都有效,但因为它不是标准的一部分,所以可能在某些特定情况下不被支持。在编写可移植性要求较高的代码时,推荐使用 `#ifndef ... #define ... #endif` 的方式


对象和类

Q4:结构体和class的区别?

A4:OOP中,主要是权限。struct 一个 a对象 和 class b对象

        a.属性 默认是public的,直接可以访问。

        b.属性 默认是private的,不可以直接访问。

Q5:拷贝构造函数是干什么用的?定义的固定格式?(入参?)

A5:就是 class Person中,让p1 = p2的。

        这样在初始化的时候,p1就可以顺承所有p2的基本信息。

        另外需要注意,使用场景可以是

        1)值传递一个入参为 class  Person p 的函数,此时会调用一次拷贝构造函数。(传参嘛,肯定要拷贝一个副本)

        2)return返回如果是 class  Person p 的话,

Q6:以下程序中哪些试图调用构造函数的方式是正确的?

A6:除了第二行都正确,第二行是会被编译器认为是声明了一个返回值为Person,没有参数的函数

这里有个比较重要的点:C#和C++很不一样的一个地方

        C++ 中 Person p1 就会调用构造函数

        C# 中,只有new的方法才会调用构造函数

Q7:以下程序调用几次拷贝构造?

void callPerson(Person p){
    return ;
}
int main(){
    Person p1;
    callPerson(p1);
    return 1;
}

A7:一次,原因是p1值传递,建立一个临时变量用来存储p1的副本

Q8:以下程序调用几次拷贝构造?(区别是返回类型是Person)

Person callPerson(Person p){
    return p;
}

int main(){
    Person p1;
    callPerson(p1);
    return 1;
}

A8:两次,在这段代码中,

        当main函数调用callPerson函数时,p1作为参数传递。建立一个临时变量用来存储p1的副本,这是拷贝构造函数第一次被调用。

        由于返回类型是Person,编译器会创建一个新的Person对象,这个对象是p的拷贝,然后将其作为函数的返回值。这是拷贝构造函数第二次被调用。

        所以,总共调用了两次拷贝构造函数。第一次是在调用callPerson时,第二次是在callPerson返回时。

Q9:构造函数调用规则如下:

        如果用户定义有参构造函数,则不在提供默认无参构造,但是会提供默认拷贝构造

        如果用户定义拷贝构造函数,c++不会再提供其他构造函数;

        问题:如果我 Person p1 = p2,这个时候会调用拷贝构造函数,还会调用构造函数吗?(假设有定义~

A9:不会了。实践出真知。可能就是没必要吧

Q10:浅拷贝和深拷贝的定义?编译器默认提供的拷贝构造函数是什么样子的?

A10:浅拷贝:赋值,即a = b;    深拷贝:在堆区重新申请空间,进行赋值操作;

编译器默认提供的拷贝构造函数是浅拷贝,也就是说我们什么都不写,会有 m_data = data 的操作

Q11:浅拷贝容易的bug是什么?

A11:浅拷贝最容易遇到的问题是容易造成指针所指向资源的重复释放。

两个解决方法 1)浅拷贝用 !=NULL 避免二次释放  2)采用深拷贝

Q12:深拷贝的具体操作?

A12:

Q13:这个构造函数的语法?

class Person
{
public:
    int age;
    string name;
    Person():age(10),name("default") {cout<<"gz"<<endl;}
    ...
}

A13:初始化列表,比较常用

Q14:this指针的用法之一是防止冲突,还有什么作用?

A14:this指针始终指向调用成员方法的对象本身。其本身是一个const class *p

        除了 this->age = age 的使用以外,还有定义成员方法时,通过返回 Person & 的方法 使用 return *this

        这种情况下可以有 func().func().func(). 这种链式调用。

        注意:为什么成员函数的返回类型 一定要是 Person & 而不是Person ?

                原因是:Person func() 的方式 return的是对象的拷贝副本,而不是对象本身。如果没有return获取到对象本体,那么程序逻辑就会出现错误。

        附:一个自己写的可以被链式调用的LinkList方法(虽然有瑕疵,他并不安全hh):

    LinkNode & AddBackNode(LinkNode &target){  // unsafe
        LinkNode *src = this;
        target.next = src->next;
        src->next = &target;
        return target;
    }

Q15:这个类内成员函数的语法?

A15:常函数,使用这个语法之后 this->属性 就不再能够改变。看着不是很优雅,但是const实在没更合适的地方加了

        常函数的语法只能在class中使用。

        常函数的主要含义是:这个函数将不能改变class中的任何成员属性。

Q16:const Person p; 这个p能否调用 Person 类中一个修改了成员属性的函数?

        进一步地,能否调用 Person 类中,一个访问了成员属性的朴素函数?

A16:均不可以。常对象只能调用常函数(见Q15)

Q17:想想链表中的有参构造会怎么做?如何优雅的写出来带默认初始值的构造函数?

A17:这个东西学名叫做初始化列表

        LinkNode() : val(0), next(nullptr){}
        LinkNode(int x) : val(x), next(nullptr){}

Q18:C++中支不支持类中类?

A18:支持。比如刷算法题时,我们会在定义链表LinkList的时候,从中建立一个LinkNode类

        这样可以把对于链表的管理(如:dummyHead和size)和节点的管理(val和next)分离开。

Q19:友元中的friend可以这么用吗?

int main(){
    friend p = Person();
    return 0;
}

A19:显然不行,friend只能在类内声明

Q20:友元的两个比较常用的操作:

1)全局函数做友元:先在原来类中声明friend,再编写全局函数,这个全局函数就可以访问到private属性

2)友元类:这个类内部的成员方法可以访问private属性

Q21:类外定义函数?可以定义构造函数吗?

A21:可以,就是要表明是哪个类(这个 Person:: 学名作用域)

class Person{
    Person();  //这里是声明
public:
    int score;
};

// 类外定义构造函数
Person::Person():score(0){}

Q22:运算符重载的本质?

A22:运算符实际上是C++为编程者预设了一个合乎规范的函数名(operator+;operator<< 等)

以下两个格式的调用语句等价:

    p3 = p1 + p2;

    p3 = p1.operator+(p2);

Q23:运算符重载的两种方式?类内重载&全局重载?为什么要学习全局重载?

A23:我们假设有Person类,首先,两种重载的方式都支持 p3 = p1 + p2 的最终写法

                全局重载:有些时候无法在类内达成重载的效果,比如重载 "<<",我们写在类内,只能达到 P<<... 的效果

而对于 cout << P,就不能完成了,必须通过全局函数对运算符进行重载(见Q24)

Q24:这个重载<<的操作正确吗?为什么要返回 ostream& 类型?

// 类外定义<<重载
ostream& Person::operator<<(ostream &out, const Person &p2){

}

A24:不对,这样会报错 Person类中没有成员 operator<<,定义的格式错了,正确格式应该是:

ostream& operator<<(ostream &out, Person &p){
    out << p.score << endl;  // 选择我们想要给流输出的内容
    return out;
}

返回类型:ostream& 这个返回的类型确保我们可以 cout << P << endl; 这也是一种链式调用的设计

入参:分别是 ostream &out, Person &p,只有这样的一前一后,才能对应 “cout << P” 的格式。


 

Q25:可以被重载的运算符大概有哪些?了解即可

A25:

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

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

相关文章

1 深度学习网络DNN

代码来自B站up爆肝杰哥 测试版本 import torch import torchvisiondef print_hi(name):print(fHi, {name}) if __name__ __main__:print_hi(陀思妥耶夫斯基)print("HELLO pytorch {}".format(torch.__version__))print("torchvision.version:", torchvi…

C++(week13): C++基础: 标准模板库 STL

文章目录 零、标准模板库 STL一、容器 (Container)1.序列式容器(1)vector2.五种遍历10.vector的迭代器失效问题 (2)deque(3)list 2.关联式容器(1)set4.set的查找(2)find() 8.set中存储自定义类型&#xff1a;三种方法 (2)multiset7.multiset的特殊操作&#xff1a;bound系列函数…

LeetCode/NowCoder-二叉树OJ练习

励志冰檗&#xff1a;形容在清苦的生活环境中激励自己的意志。&#x1f493;&#x1f493;&#x1f493; 目录 说在前面 题目一&#xff1a;单值二叉树 题目二&#xff1a;相同的树 题目三&#xff1a;对称二叉树 题目四&#xff1a;二叉树的前序遍历 题目五&#xff1a;另…

Python | Leetcode Python题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; class Solution:def hIndex(self, citations: List[int]) -> int:n len(citations)left 0; right n - 1while left < right:mid left (right - left) // 2if citations[mid] > n - mid:right mid - 1else:left mid 1retur…

C语言之2048小游戏理解分析

目录 游戏程序思维导图&#xff1a; ​编辑 功能介绍&#xff1a; 代码管理&#xff1a; 主函数&#xff1a; 头文件&#xff1a; 游戏程序思维导图&#xff1a; 功能介绍&#xff1a; 按键W --------------- 向上 按键A --------------- 向左 按键S --------------- 向…

科技云报道:算网筑基AI注智,中国联通如何讲出AI时代的“新故事”?

科技云报道原创。 AI从未停止进化&#xff0c;也从未停止给人类带来惊喜。 从ChatGPT代表的文生文、Dall-E代表的文生图&#xff0c;到Sora代表的文生视频&#xff0c;Suno为代表的文生音乐&#xff0c;生成式AI的“暴力美学”持续突破内容生产的天花板&#xff0c;大模型技术…

【黑马java基础】特殊文件,日志

目录 特殊文件&#xff1a;Properties属性文件特点、作用使用Properties读取属性文件里的键值对数据使用properties把键值对数据写到属性文件中去案例 特殊文件&#xff1a;XML文件概述读取XML文件中的数据把数据写出到XML文件中去补充知识&#xff1a;约束XML文件的编写[了解]…

打卡第21天------二叉树

我现在每天都是在与时间赛跑&#xff0c;分秒必争&#xff0c;不想浪费一点我自己的时间。 希望通过算法训练营可以把我自己的逻辑思维建立起来&#xff0c;把自己的算法能力给提上去。 一、修剪二叉搜索树 题目链接&#xff1a;669. 修剪二叉搜索树 题目描述&#xff1a; 给…

最优化原理(笔记)

内积是线性代数运算的一个结果&#xff0c;一行*一列。 内积的性质&#xff01; 什么是范数&#xff1f;&#xff1f;&#xff1f; 对称矩阵&#xff1a;关于主对角线对称&#xff01; 正定对称矩阵&#xff1a; 二阶导是正定的&#xff0c;f(x)就是严格的凸函数&#xff01;&a…

element的el-autocomplete带输入建议搜索+搜索匹配文字高亮显示

element的el-autocomplete带输入建议搜索搜索匹配文字高亮显示 直接上代码 // vue代码块 添加插槽<el-autocompleteclearableplaceholder"请输入关键词进行搜索"input"searchInput"v-model"searchInputData":fetch-suggestions"queryS…

Android APP 音视频(02)MediaProjection录屏与MediaCodec编码

说明&#xff1a; 此MediaProjection 录屏和编码实操主要针对Android12.0系统。通过MediaProjection获取屏幕数据&#xff0c;将数据通过mediacodec编码输出H264码流&#xff08;使用ffmpeg播放&#xff09;&#xff0c;存储到sd卡上。 1 MediaProjection录屏与编码简介 这里…

【测开能力提升-Javascript】JavaScript运算符流程结构

1. 递增递减运算符 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Title</title><script>// 前置递增运算符var age10age //类似于ageage1&#xff0c; 先加1后返回值alert(age)// 后置…

【数据结构 | 哈希表】一文了解哈希表(散列表)

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; &#x1f923;本文内容&#x1f923;&a…

【SQL语句大全(MySQL)】

SQL语法 添加删除修改查询基本查询条件查询分组函数/聚合函数分组查询排序分页查询&#xff08;限制查询&#xff09;多表查询连接查询根据年代分类连接查询根据连接方式分类1、内连接2、左外连接3、右外连接 多张表连接的语法格式 嵌套查询 SQL语句书写顺序 添加 INSERT INTO…

什么是STP环路保护

在运行生成树协议的网络中&#xff0c;根端口和其他阻塞端口状态是依靠不断接收来自上游设备的BPDU维持。当由于链路拥塞或者单向链路故障导致这些端口收不到来自上游交换设备的BPDU时&#xff0c;设备会重新选择根端口。原先的根端口会转变为指定端口&#xff0c;而原先的阻塞…

2019年9月全国英语等级考试第三级笔试真题

2019年9月全国英语等级考试第三级笔试真题

vue3.0学习笔记(三)——计算属性、监听器、ref属性、组件通信

1. computed 函数 定义计算属性&#xff1a; computed 函数&#xff0c;是用来定义计算属性的&#xff0c;计算属性不能修改。 计算属性应该是只读的&#xff0c;特殊情况可以配置 get set 核心步骤&#xff1a; 导入 computed 函数 执行函数 在回调参数中 return 基于响应…

尚品汇-sku存入Redis缓存(二十三)

目录&#xff1a; &#xff08;1&#xff09;分布式锁改造获取sku信息 &#xff08;2&#xff09;使用Redisson 分布式锁 AOP实现缓存 &#xff08;3&#xff09;定义缓存aop注解 &#xff08;1&#xff09;分布式锁改造获取sku信息 前面学习了本地锁的弊端&#xff0c;…

Springboot validated JSR303校验

1.导入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-validation</artifactId></dependency> 2.测试类 package com.jmj.gulimall.product.testC;import lombok.Data;import javax.val…

《0基础》学习Python——第二十讲__网络爬虫/<3>

一、用post请求爬取网页 同样与上一节课的get强求的内容差不多&#xff0c;即将requests.get(url,headershead)代码更换成requests.post(url,headershead),其余的即打印获取的内容&#xff0c;如果content-typejson类型的&#xff0c;打印上述代码的请求&#xff0c;则用一个命…