首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >C++编程之路:类和对象(下)

C++编程之路:类和对象(下)

作者头像
用户11970727
发布2025-12-30 16:04:01
发布2025-12-30 16:04:01
1330
举报
文章被收录于专栏:C语言C语言

Hello大家好! 很高兴与大家见面! 给生活添点快乐,开始今天的编程之路。

一 再探构造函数【前面我们讲过构造函数初始化的两种方法一种在函数体中一种使用初始化列表这里我们补充初始化列表的使用】

1定义/特点:

•之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式。【注意虽然这种方法可行但不是万能,例如当我们想在初始化的同时输出一些东西。这时候就只能在函数体中进行,所以在现实中我们对两种方法同时使用】 •每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。 •引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始化,否则会编译报错。【因为这几个变量必须在定义的同时初始化,而初始化列表就是成员变量初始化的地方】 •C++11⽀持在成员变量声明的位置给缺省值(缺省值可以是常量也可以是一个表达式只有可以返回相应的值即可),这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的(如果初始化列表中有,就不会使用缺省值)。 •尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。 •初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关。建议声明顺序和初始化列表顺序保持⼀致。

2 构造函数在函数体和使用初始化列表两种结合使用
3当自定义类型没有默认构造,此时必须使用初始化列表初始化
4在(C++11 )中初始化列表支持给缺省值
5 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆关

下面我们来看一到题理解一下:

结果:

分析一下,首先这道题和缺省值没什么关系,因为既然a1,a2都显示在初始化列表里面了那就不需要用缺省值走初始化列表了。现在需要注意一点,初始化的顺序和声明的顺序保持一致。那也就是说先初始化a2,再初始化a1。那这样的话a2在初始化的时候他的值和a1的值相等,而a1此时的值是随机值,在这之后a1进行初始化,他的值等于1.

经过上述分析,输出结果为1和随机值。

6初始化列表总结:

⽆论是否显⽰写初始化列表,每个构造函数都有初始化列表; ⽆论是否在初始化列表显⽰初始化成员变量,每个成员变量都要⾛初始化列表初始化;

二 类型转换

1定义/特点

•C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。 •构造函数前⾯加explicit就不再⽀持隐式类型转换。 •类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持。 •作用:隐式类型转换实际上是极大程度方便我们编写程序的。特别是在传参的时候,可以不用创建对象,例如如果我们对于数据结构中的栈,假如此时我们想传类类型的参数这时就可以使用隐式类型转换。 •要注意类型的转换的过程中可能生成临时变量,要使用const修饰

2类型转换的过程

对于A x=10这句,这是调用构造函数而不是=的运算符重载。但是这种构造并不是简单的构造。他其实是先用10构造出一个临时对象,在把临时对象拷贝构造给x(这里用的拷贝构造是编译器自己生成的拷贝构造),但是经过编译器优化之后,优化成了直接构造(这一过程叫优化构造)。这其实就是隐式类型转换。[这一过程很难观察到,感兴趣的可以在Gcc环境下用相关命令关闭构造优化,便可以观察这一过程】

这段代码对于const A& tt2=1;这一句,如果我们去掉const就会发现编译报错,这是为什么?

我们来分析一下。首先1创建临时对象,由于临时对象具有常性,如果直接用A&的话就会造成权限放大的问题,编译报错。所以我们必须const引用。

3 类型转换的使用【支持单个参数、多个参数(多个用{}括起来)、自定义类型转换未自定义类型】

三 static成员【变量/函数】(静态成员)

1定义/特点

•⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化(因为静态变量存在静态区,如果在类内给值,给的时缺省值,而缺省值是用于走初始化列表时使用,而静态变量不属于对象的一部分【不走初始化列表】)。 •静态成员变量为所有类对象所共享,不属于某个具体的对象(所以在计算对象大小时不计数其大小),不存在对象中,存放在静态区。【因为像函数等其他类型在文件编译和链接的过程中会生成相应的符号表,而静态成员变量这一过程是不会进入符号表的所以静态成员变量为所有类对象所共享,此时为了防止其在不同的类中同时使用我们一般在类中声明在类外定义(初始化)】 •⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。 •静态成员函数中可以访问其他的静态成员,但是不能访问⾮静态的,因为没有this指针。 •⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数。 •突破类域就可以访问静态成员,可以通过(类名::静态成员) 或者(对象.静态成员)来访问静态成员变量和静态成员函数。 •静态成员也是类的成员,受public、protected、private 访问限定符的限制。 •静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表。 •注意用static修饰便成为静态成员,虽然的所出都作用域可能不同,但是静态成员变量的生命周期永远是全局的(和全局的生命周期一样)

2 static成员使用要注意

•静态成员变量私有化怎么访问通过Get函数,但是如果一个函数要访问呢?此时如果要创建对象,或者传参都麻烦,此时就可以定义静态成员函数,指定类域即可访问。(静态成员变量和静态成员函数一般时成对出现的)。 •静态成员变量的优点:因为其要在规定的地方初始化(定义)已经做到声明定义分离,所以不存在多个文件引发冲突问题。2其受到类域限定,又受到访问限定符限定。 •其优点是尽量让我们少用全局变量,使用全局变量的问题:1如果在多个文件中包含,就会引发链接问题(起冲突),此时就要使用static修饰,而static只在当前文件可见(此时就有一个问题,例如在头文件中定义一个静态变量a,又在别的文件中定义一个变量a,这两个变量是不一样的)2谁的可以改变 •局部静态成员变量只会在第一次运行到的时候构造(初始化),并且不管调用多少次也只会初始化一次,析构是函数结束后,因为其生命周期和全局一样。

3使用案例:

3.1静态成员变量⼀定要在类外进⾏初始化

3.2静态成员函数和静态成员变量的使用

3.3静态成员函数和静态成员变量的访问方式

四 友元

1特点/定义:

•友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。 外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数(在类内声明,此时没有this指针)。 友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制(因为友元仅仅是⼀种声明,他不是类的成员变量/函数,一般放在起始位置)。 ⼀个函数可以是多个类的友元函数。 友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。 友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。 友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。 •有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多⽤。

2友元使用注意:

•全局函数声明成友元函数应该声明定义分离复防止多个文件中使用起冲突,或者定义成inline因为inline函数会展开不会进入符号表。 •如果一个函数要在两个及以上的类中友元,此时类要前置声明(因为存在互相干扰的问题)

3友元的使用:

3.1友元是一种声明,可以用过友元声明突破访问限定:

例如上面这一串代码,我们把sum函数声明成友元,那么sum函数就可以访问类A里面的私有成员。

3.2友元类的关系是单向的、友元类关系不能传递,所以我们一定要弄清谁是谁的友元不能随意通过友元访问:

我们把classA 声明为B的友元,就可以通过A突破访问限定符直接访问B的私有成员。【需要注意的是,友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元,所以我们一定要弄清谁是谁的友元,比如A是B的友元,那么就可以通过A访问B。顺序不能反。另外就是上面两串代码中都是声明友元的那一部分放在上面(先定义)】。

五 内部类

1特点/定义:

•如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。 •内部类默认是外部类的友元类。 •内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地⽅都⽤不了。

2内部类的使用:

六 匿名对象

1特点/定义:

•⽤类型(实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。 •匿名对象⽣命周期只在当前⼀⾏,⼀般临时定义⼀个对象当前⽤⼀下即可,就可以定义匿名对象。

七 对象拷⻉时的编译器优化

1特点/定义:

• 现代编译器会为了尽可能提⾼程序的效率,在不影响正确性的情况下会尽可能减少⼀些传参和传返回值的过程中可以省略的拷⻉。 •如何优化C++标准并没有严格规定,各个编译器会根据情况⾃⾏处理。当前主流的相对新⼀点的编译器对于连续⼀个表达式步骤中的连续拷⻉会进⾏合并优化,有些更新更"激进"的编译器还会进⾏跨⾏跨表达式的合并优化。 •linux下可以将下⾯代码拷⻉到test.cpp⽂件,编译时⽤ g++ test.cpp -fno-elide constructors 的⽅式关闭构造相关的优化。

本篇文章作为c++基础教学入门指南的第四篇,带大家认识和简单使用c++本篇文章就到此结束,欢迎大家订阅我的专栏,欢迎大家指正,希望有所能帮到读者更好理解C++相关知识 ,觉得有帮助的还请三联支持一下~后续会不断更新C/C++相关知识,我们下期再见。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-11-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 再探构造函数【前面我们讲过构造函数初始化的两种方法一种在函数体中一种使用初始化列表这里我们补充初始化列表的使用】
    • 二 类型转换
    • 三 static成员【变量/函数】(静态成员)
    • 四 友元
    • 五 内部类
    • 六 匿名对象
    • 七 对象拷⻉时的编译器优化
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档