类和对象——初始化列表

chatgpt/2023/9/26 13:56:21

目录

初始化列表

注意

单/多参数传入

explicit关键字

匿名函数


先前,我们知道有构造函数——用于给各成员变量一个初始值。

但是仍然不能称为是初始化,因为初始化只能初始化一次,但是构造函数里可以多次赋值

初始化列表

以日期类Date为例,进行一个初始化列表

class Date
{
public:
//初始化列表—每个成员定义的地方Date(int year, int month, int day):_year(year) //成员变量会被赋值为括号内相应的值, _month(month), _day(day),_x(1){//_day=day;//此处只能写在中括号里,中括号外必须要有' () '去定义    }  //中括号内实现其他代码
private:int _year;int _month;int _day;const int _x=10;//const修饰的变量必须要在定义的时候初始化-后续不能修改,总之在类里必须有个地方进行赋值初始化
};

注意

1.缺省值是赋予初始化列表的

2.若初始化列表没有显示给值,就用这个缺省值

3.如果显示给值了,就不用这个缺省值(会先赋值缺省值,如果在列表里重新定义,就会重新赋值)

4.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后 次序无关

单/多参数传入

单参数直接用 ' () '或者用' = '进行拷贝构造,多参数不仅可用' () ' 还能用' {} '

//单参数
class A
{
public:A(int i):_a(i){cout << "a(int i)" << endl;}
private:int _a;
};
//多参数
class B
{
public:B(int b1, int b2)//explicit B(int b1, int b2):_b1(b1), _b2(b2){cout << "B(int b1, int b2)" << endl;}
private:int _b1;int _b2;
};int main()
{const A& ref = 2;B bb1 (1, 2);B bb2 = { 2,2 };const B& ref2 = { 3,3 };//相同空间用引用,需转换类型,加const修饰return 0;
}

explicit关键字

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

class A
{
public://explicit A(int i)//在构造函数这里加上explicit,可以防止隐式转换——这样主函数的两个转换就不能使用了A(int i):_a(i){cout << "A(int i)" << endl;}A(const A& aa):_a(aa._a){cout << "A(const A& aa)" << endl;}~A(){cout << "Delete" << endl;}
private:int _a;
};int main()
{A aa1(1);/单参数构造函数的隐式类型转换//用2调用A构造函数,先生成一个临时对象,再用这个对象去拷贝构造aa2//编译器会优化,优化用2直接构造A aa2 = 2;//结果是直接构造,而不是先对2进行了拷贝构造,再把这个对象赋值给aa2//2会进行隐式类型转换,过程中会生成临时对象,具有常性,所以需要const去修饰const A& ref = 2;//2转换,生成了一个临时对象具有常性,需要用const来修饰return 0;
}

用explicit修饰构造函数,将会禁止构造函数的隐式转换。

匿名函数

顾名思义,就没进行命名的对象——生命周期仅存在于定义的那一行

    A aa6(6);//有名——生命周期在当前局部域A (7);//匿名——生命周期只在这一行//运行后发现的确调用了一次析构,说明出了这一行就会销毁//先定义再传入数据,代码量多SeqList s;s.PushBack(aa6);//用匿名对象传,直接放入想要的数据s.PushBack(A(8));

除此之外,匿名函数还有其他用法

class Solution {
public:int Sum_Solution(int n) {// ...cout << n << endl;return n;}
private:
};int main()
{Solution s1;s1.Sum_Solution(10);Solution().Sum_Solution(100);//这种方法无需定义一个对象,直接赋值,调用类里的函数。return 0;}

Static成员

现在我们知道,一个类里边可以建立很多个对象,那我们是否可以统计出累积创建了多少个对象,并且执行到某一处正在使用的还有多少个对象

引入

可以用以下代码

//全局变量
int n=0;
int m=0;
class A
{A(){++n;++m;}A(const  A& t){++n;++m;}~A(){--m;}void Print(){cout<<m<<" "<<n<<endl;}
private:}
int main()
{A aa1;A aa2;cout << n << " " << m << endl;//共有情况,非privateA();cout << n << " " << m << endl;Func(aa1);cout << n << " " << m << endl;return 0;
}

结果:

 修正

但是如果将n和m放在全局变量的话,容易被修改,那怎么解决呢?——放入类里,仅需要改变private里的内容

class A
{
public:{//....}
//private://静态成员变量属于所有A对象,属于所有类/*int n=0 ;//创建int m=0 ;//正在使用 */err,因为这样的话,每个对象都会有一个m和n,但我们仅需要一个全局的,所有对象共有的static int n;static int m;}int A::m=0;
int A::n=0;

访问形式

int main()
{A aa1;A aa2;cout << A::n << " " <<A:: m << endl;//共有情况,非privatecout << aa1.n << " " << aa1.m << endl;return 0;
}

static定义的特点

1.static定义的变量处于静态区里,不参与类大小的计算

sizeof(A);//———— 1

因为不参与类大小的计算,所以内存可视为0,但是类的构建是需要内存的,所以最少会分配一个字节的空间

int main()
{A* ptr = nullptr;cout << ptr->n << " " << ptr->m << endl;//为什么行得通?return 0;
}

因为此处n和m存在于静态区,类似于成员函数的公共代码区,所以一样可以访问。

2.静态成员变量属于所有A对象,属于所有类

3.在类中由于用static定义了——所以属于全局,所以不能给缺省值

4.静态变量不能走初始化列表,不属于对象里,故不能给缺省值,是在静态区里的

5.限制了,不能在外边直接访问并且修改,除非得到m/n的别名,访问方式同其他类' :: '

' . '

static静态成员函数

因为n和m是属于所有A对象,属于所有类,所以需要调用一次类去打印

若用匿名函数

int main()
{A();//能否用匿名函数去打印?A();A::Print();return 0;
}

若用匿名函数,那么同样也会调用一次类,那么就会对数据造成误差。

此时就要用到静态成员函数

static void Print(){//x++; //不能访问非静态,因为没有this指针cout << m <<" "<< n << endl;}

静态成员函数特点

1.不具有this指针

2.不能访问非静态变量(仅能访问static定义的变量)

倘若想对m和n进行修改呢???——就需要静态引用返回——既不会额外改变m也不会直接改变m

static int& GetM(){return m;}
++A::GetM();

例题

现在我们知道了通过每次的构造函数,可以实行计数

 (求1+2+3+...+n_牛客题霸_牛客网)

我们需要建立两个类,一个类用于返回结果,另一个用来统计——怎么统计?——通过每次的构造实现n个有序数字的累加

class Sum
{
public:Sum()//构造函数,开创一次就进入一次{_ret+=_i;_i++;}static int GetRet(){return _ret;}private:static int _ret;//用static修饰,这样可以保证所有对象共用这个_retstatic int _i;
};int Sum::_ret=0;
int Sum::_i=1;
class Solution
{
public:int Sum_solution(int n){Sum a[n]return Sum::GetRet();}
};

友元函数

对于有private限定符的类,若是某个定义在类外的函数需要调用类内部的数据,那么就需要友元函数

以输出流/输入流为例

class Date
{//友元声明——这样可以在外部访问私密对象//friend void operator<<(ostream& out, const Date& d);friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);
public:{//..}
private:{}
}

内部类

特点/定义

1.一个类定义在另一个类的内部

2.内部类是一个独立的类,不受限制,且是外部类的友元

class C
{
public:class D{public:void FuncD(){;}private:int _d;};
private:int _c;
};sizeof(C);//  ——4

读取类C大小为4——因为内部类D还是独立的,所以读取的还是C的大小。

3.内部类是外部类的友元,内部类可以读取外部类的变量

class C
{
public:class D{public:void FuncD(){C cc;cc._c = 1;//内部类D可以直接访问外部类C的私有成员变量}private:int _d;};void func(){D dd;}
private:int _c;
};

4.public不能去掉,这样的话D类就不属于C类的公共区域里,

int main()
{C::D dd1;//但是定义还是得用C类域内部的D类定义//若去掉public,那么D类不是公共的,就不能调用cc.func();//也不能调用,因为func是属于D类的,但是D类不公共return 0;
}

内部类实现循环

再次谈回上边的例题,这次可以通过内部类来实现循环

(求1+2+3+...+n_牛客题霸_牛客网 (nowcoder.com))

class Solution {class Sum{public:Sum(){_ret+=_i;_i++;}};
public:int Sum_Solution(int n) { Sum a[n];return _ret;}
private:static int _ret;static int _i;
};int Solution::_ret=0;
int Solution::_i=1;

同理,还是需要用到static静态成员,将每次的_ret和_i 进行保存在全局变量里

本质上还是用到了构造函数的访问进行累加

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

如若内容造成侵权/违法违规/事实不符,请联系郑州代理记账网进行投诉反馈,一经查实,立即删除!

相关文章

【Golang 接口自动化08】使用标准库httptest完成HTTP请求的Mock测试

目录 前言 http包的HandleFunc函数 http.Request/http.ResponseWriter httptest 定义被测接口 测试代码 测试执行 总结 资料获取方法 前言 Mock是一个做自动化测试永远绕不过去的话题。本文主要介绍使用标准库net/http/httptest完成HTTP请求的Mock的测试方法。 可能有…

软件测试员,面试常见的18个问题(记得收藏!)

软件测试面试18个常见问题汇总 Q1&#xff1a;项目中相关需求问题&#xff0c;测试可以直接和客户沟通吗&#xff1f; A1&#xff1a;可以&#xff0c;最初与客户沟通需求时&#xff0c;测试人员直接参与&#xff0c;所以我们可以直接和客户方的代表开会进行沟通。 A2&#xff…

使用gadl对土地利用栅格重分类

要使用Python语言进行土地利用栅格的重分类&#xff0c;可以使用gadl库&#xff08;GDAL的Python绑定&#xff09;来实现。gadl库提供了一组功能强大的函数和类&#xff0c;可用于读取、处理和分析栅格数据。 首先&#xff0c;确保已经安装了gadl库。可以使用以下命令通过pip进…

别再分库分表了,来试试它吧

什么是NewSQL传统SQL的问题 升级服务器硬件数据分片NoSQL 的问题 优点缺点NewSQL 特性NewSQL 的主要特性三种SQL的对比TiDB怎么来的TiDB社区版和企业版TIDB核心特性 水平弹性扩展分布式事务支持金融级高可用实时 HTAP云原生的分布式数据库高度兼容 MySQLOLTP&OLAP&#xff…

pyspark 判断 Hive 表是否存在

Catalog.tableExists(tableName: str, dbName: Optional[str] None) → booltableName:表名 dbName&#xff1a;库名(可选) return&#xff1a;bool 值 spark SparkSession \.builder \.appName(tableExists) \.config(spark.num.executors, 6) \.config(spark.executor.memo…

javadoc注解及maven-javadoc-plugin插件

一、javadoc注解标记&#xff1a; author&#xff1a;作者-类、接口级别 version&#xff1a;版本-类、接口级别 deprecated&#xff1a;不推荐使用的方法 param&#xff1a;方法、构造函数的参数 return&#xff1a;方法的返回类型 see&#xff1a;用于指定参考的内容&am…

银河麒麟V10系统忘记密码解决

1、正常开机等待系统进入GRUB界面&#xff0c;按下e键&#xff0c;如下图&#xff1a; 2、进入编辑文件&#xff1a; 3、 修改ro为rw 然后再行尾添加空格输入&#xff1a;consoletty init/bin/bash 输入完成按&#xff1a;ctrlx或F10进入修改密码阶段 4、修改密码&#xff1a;…

Redis如何实现排行榜?

今天给大家简单聊聊 Redis Sorted Set 数据类型底层的实现原理和游戏排行榜实战。特别简单&#xff0c;一点也不深入&#xff0c;也就 7 张图&#xff0c;粉丝可放心食用&#xff0c;哈哈哈哈哈~~~~。 1. 是什么 Sorted Sets 与 Sets 类似&#xff0c;是一种集合类型&#xff…
推荐文章