C++入门:类和对象(后)

news/2024/11/29 22:44:12/

目录

前言:

一:static成员

(1)概念

(2)特性

(3)例子

二:explicit关键字 

三:内部类

(1)概念

(2)特性

(3)实例

四:匿名对象

(1)概念

(2)特性

(3)实例

五:拷贝对象时的一些编译器优化

(1)引入

(2)更多例子

代码:


前言:

C++专栏内容连贯,没展开讲的重要内容都在专栏往期。

为方便语法学习,直接展开std命名空间。

个人主页链接:派小星233的博客_CSDN博客-初阶数据结构,C语言,C++初阶领域博主 


一:static成员

(1)概念

  • 声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量,静态成员变量一定要在类外进行初始化
  • 用static修饰的成员函数,称之为静态成员函数。

(2)特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明
  3. 类静态成员即可用类名::静态成员 或者 对象.静态成员来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

(3)例子

问题:实现一个类,计算程序中创建出了多少个类对象。 

代码:

class A
{
public:A() //构造{ ++_scount; }A(const A & t) //拷贝 { ++_scount; }static int GetACount() { return _scount; }
private://声明这个静态变量是属于这个类的,没有定义static int _scount;
};//定义并加域限定符(域限定也是符号表规则之一,不加的话类中的_scout只有声明)
int A::_scount = 0;int main()
{cout << A::GetACount() << endl;A a1, a2;A a3(a1);//构造了三次,属于类A的静态变量加了3cout << A::GetACount() << endl;return 0;
}


二:explicit关键字 

我们看下面这段代码:
class A
{
public:A(int a = 0,int b = 0):_a(a),_b(b){}
private:int _a;int _b;
};int main()
{A a1 = 50;return 0;
}

上面的代码和结果说明了这样一个现象:

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用

构造函数的隐式转换有的时候很灵活,有的时候却会导致代码的可读性下降,explicit关键字的作用就是修饰构造函数,禁止类型转换

代码:

//这段代码编译不通过
class Date
{
public:// 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用// explicit修饰构造函数,禁止类型转换---explicit去掉之后,代码可以通过编译explicit Date(int year):_year(year){}/*// 2. 虽然有多个参数,但是创建对象时后两个参数可以不传递,没有使用explicit修饰,具有类型转换作用// explicit修饰构造函数,禁止类型转换explicit Date(int year, int month = 1, int day = 1): _year(year), _month(month), _day(day){}*/Date& operator=(const Date& d){if (this != &d){_year = d._year;_month = d._month;_day = d._day;}return *this;}
private:int _year;int _month;int _day;
};
void Test()
{Date d1(2022);// 用一个整形变量给日期类型对象赋值//构造函数没用explicit修饰时实际编译器背后会用2023构造一个无名对象,最后用无名对象给d1对象进行赋值d1 = 2023;// 将1屏蔽掉,2放开时则编译失败,因为explicit修饰构造函数,禁止了单参构造函数类型转换的作用
}

 

 


三:内部类

(1)概念

如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,
它不属于外部类
内部类就是外部类的友元类,内部类可以访问外部类中的所有成员。但是外部类不是内部类的友元,不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限。

(C++内部类并不常用)

(2)特性

  1. 内部类可以定义在外部类的public、protected、private都是可以的。(如果定义在private或者protected,则外部不可定义内部类的对象)
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系

(3)实例

代码:
class A
{
private:static int k;int _a = 0;
public:class B // B天生就是A的友元{public:void foo(const A& a){//B类是A类友元,可以访问Acout << k << endl;cout << a._a << endl;}};
};int A::k = 1;int main()
{//虽然说类A对类B并没有访问权限,但是类B的定义是在A的域里面的//定义类B实例化对象时需要加上域限定符A::B b;A a1;b.foo(a1);return 0;
}

四:匿名对象

(1)概念

匿名对象指的是没有被赋予任何名称的对象,它们通常是在方法调用时临时创建的,并且只能被引用一次。虽然匿名对象没有名称,但它们仍然是一个完整的对象,具有对象的所有属性和方法。需要注意的是,由于没有名称,当使用匿名对象时无法再进行其他操作或访问该对象。

(2)特性

  1. 匿名对象没有名字,在定义对象时,不需要为其分配变量名,可以直接使用,且使用完毕后不需要释放内存,系统会自动回收。

  2. 匿名对象一般用于临时的对象操作,可以在一些函数中直接使用,无需定义变量。

  3. 匿名对象一般不能用于多次操作。如果需要多次操作一个对象,应当定义具名对象,否则代码会难以维护。

  4. 在定义匿名对象时,无法传递对象参数执行对象的构造函数

  5. 匿名对象的生命周期只有一条语句

(3)实例

代码:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};class Solution {
public:int Sum_Solution(int n) {//这里可以实现一系列计算,比方求n的阶乘//…………return n;}
};int main()
{A aa1;// 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义//A aa1();// 但是我们可以这么定义匿名对象,匿名对象的特点不用取名字,// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数A();A aa2(2);// 匿名对象在这样场景下就很好用Solution().Sum_Solution(10);return 0;
}

五:拷贝对象时的一些编译器优化

(1)引入

注意:这部分的优化取决于编译器,大部分的编译器是存在优化的。

 但对象复杂的类对象,一个对象往往很大,这个时候拷贝的代价十分大,编译器会在保证安全的情况下进行优化。比如:使用去A函数构造一个对象,然后传值返回main函数去拷贝构造一个新对象。在未优化的情况下,你先拷贝了一份存储在预留的部分,然后在回收空间前又拷贝预留的一份到main函数栈帧中;这个行为在编译器看来是可以优化的,于是编译器直接拷贝了一份到main函数栈帧中,省去了在预留空间中的一次拷贝。(其他的连续拷贝也类似)

(2)更多例子

代码:

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}A& operator=(const A& aa){cout << "A& operator=(const A& aa)" << endl;if (this != &aa){_a = aa._a;}return *this;}~A(){cout << "~A()" << endl;}
private:int _a;
};void f1(A aa)
{}
A f2()
{A aa;return aa;
}
int main()
{// 传值传参A aa1;f1(aa1);cout << endl;// 传值返回f2();cout << endl;// 隐式类型,连续构造+拷贝构造->优化为直接构造f1(1);// 一个表达式中,连续构造+拷贝构造->优化为一个构造f1(A(2));cout << endl;// 一个表达式中,连续拷贝构造+拷贝构造->优化一个拷贝构造A aa2 = f2();cout << endl;// 一个表达式中,连续拷贝构造+赋值重载->无法优化aa1 = f2();cout << endl;return 0;
}

 


http://www.ppmy.cn/news/537185.html

相关文章

012-从零搭建微服务-接口文档(二)

写在最前 如果这个项目让你有所收获&#xff0c;记得 Star 关注哦&#xff0c;这对我是非常不错的鼓励与支持。 源码地址&#xff08;后端&#xff09;&#xff1a;https://gitee.com/csps/mingyue 源码地址&#xff08;前端&#xff09;&#xff1a;https://gitee.com/csps…

SVN教程

SVN使用教程总结 SVN简介&#xff1a; 为什么要使用SVN&#xff1f; 程序员在编写程序的过程中&#xff0c;每个程序员都会生成很多不同的版本&#xff0c;这就需要程序员有效的管理代码&#xff0c;在需要的时候可以迅速&#xff0c;准确取出相应的版本。 Subversion是什么&am…

【裸机开发】IRQ 中断服务函数(二)—— 全局中断初始化

实现了 IRQ 中断服务函数的汇编部分以后&#xff0c;接下来我们要使用C代码实现IRQ中断服务函数的具体逻辑&#xff0c;主要包含初始化和中断处理两部分。 全局中断初始化&#xff08;全局中断使能、IRQ中断使能&#xff09;具体中断处理逻辑实现 目录 一、全局中断初始化&am…

为什么要写这个带点玄幻气息的英语单词记忆博客

&#x1f31f;博主&#xff1a;命运之光 ☀️专栏&#xff1a;英之剑法&#x1f5e1; ❤️‍&#x1f525;专栏&#xff1a;英之试炼&#x1f525; ☀️博主的其他文章&#xff1a;点击进入博主的主页 &#x1f433; 开篇想说的话&#xff1a;开学就大三了&#xff0c;命运之光…

局域网聊天连接全集

布谷鸟2008 局域网聊天工具2008 5.01 下载- 华军软件园- 网络工具 ... 《布谷鸟2008 第二版》局域网聊天通讯办公软件&#xff0c;免费使用&#xff0c;无须注册。可实现局域网络间跨网段的聊天、群聊、和传送文件外&#xff0c;还包括&#xff1a;“日程安排”“通讯录”“个人…

公司禁用QQ之旅

公司要求上班时间禁止使用QQ等聊天工具&#xff0c;刚开始时想着直接把QQ使用的端口禁用掉&#xff0c;真正去实施时就发现问题来了&#xff0c;BT的腾讯&#xff0c;居然使用的是4000&#xff0c;8000&#xff0c;80端口&#xff0c;晕死&#xff0c;这些端口还真的关不得&…

公司禁用U盘的方法总结

U盘虽好&#xff0c;未必被公司管理者待见。因为员工乱插U盘会带来潜在病毒风险&#xff0c;最关键的是担心员工把重要文件通过优盘拷走了。公司禁用U盘是绕不过去的一道坎。 总结下常见的禁用U盘的方法&#xff1a; 方法一&#xff0c;物理封堵法&#xff1a; 把机箱所有US…

CoreMark 跑个分:OrangePi5 RK3588S

一、 Orange Pi 5 简介 Orange Pi 5 采用了瑞芯微 RK3588S 新一代八核 64 位处理器&#xff0c;具体为四核A76四核A55&#xff0c;采用了 8nm 工艺设计&#xff0c;主频最高可达 2.4GHz&#xff0c;集成 ARM Mali-G610 MP4 GPU&#xff0c;内嵌高性能 3D 和 2D 图像加速模块&am…