欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 家装 > 240416 初始化列表 构造与隐式类型转换 static成员 友元 内部类

240416 初始化列表 构造与隐式类型转换 static成员 友元 内部类

2024/10/25 13:24:29 来源:https://blog.csdn.net/FuLLovers/article/details/141995713  浏览:    关键词:240416 初始化列表 构造与隐式类型转换 static成员 友元 内部类

一、初始化列表

1、认识

【P】Stack不具备默认构造,MyQueue也无法生成默认构造
【S】引入初始化列表

MyQueue(int n):_pushst(n),_popst(n),_size(0)
{}

初始化列表本质上可以理解为每个对象中成员定义的地方
所有成员既可以在初始化列表初始化,也可以在函数体初始化,下面的只能在初始化列表处初始化:

  1. 引用
  2. const
  3. 自定义类型成员没有默认构造(必须显式传参调构造)

const变量必须在初始化列表中定义,因为const变量只有一次初始化的机会,必须在定义时初始化

2、注意事项

  • 初始化列表无论写不写,每个成员变量都会先走一遍
  • 自定义成员会调用默认构造
  • 内置类型有的缺省值的用缺省值,没有的话看编译器,有的编译器会处理

先走初始化列表,再走函数体
【实践中】尽可能用初始化列表初始化,不方便再用函数体初始化

public:MyQueue():_size(1) //显式写了就不用缺省值了{}
private:int _size = 0; //缺省值(给初始化列表使用)

【注】声明处的值是缺省值,并非定义,而是提供给初始化列表时使用的

3、初始化顺序

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

class A {
public:A(int a):_a1(a),_a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}
private: // 初始化顺序与声明次序相同int _a2;int _a1;
};int main() {A aa(1);aa.Print();return 0;
}输出结果:
1 -858993460

二、单/多参数构造函数与隐式类型转换

在类中,声明成员变量给缺省值时也可以利用到【单/多参数构造函数与隐式类型转换】

B bb1(10);
// 拷贝构造
B bb2 = bb1;// 隐式类型转换
// 内置类型转为自定义类型(单参数构造函数支持)
B bb3 = 1;// 1构造一个B的临时对象,再用这个临时对象拷贝构造bb3
B bb4 = 3.14;
B bb5 = 'a';
//B bb6 = "abcd"; // 字符串不可以
// 临时变量具有常性
const B& bb6 = 3.14;// bb6引用的是用3.14构造的临时对象
// 编译器遇到连续构造和拷贝构造->优化为直接构造// 应用场景// 原本
Stack st1;
B bbo(1);
st1.Push(bbo);
cout << endl;
// 简化后
st1.Push(2);// 又例
list<string> lt;
string s1("abc");
lt.push_back(s1);
// 简化后
lt.push_back("abc");C cc1(10, 20);
C cc2 = { 100,200 };
//C cc2 = (100,200);// 错误写法,但如果有单参数构造函数可能不会报错,逗号表达式只出一个结果
const C& cc3 = { 1000,2000 };Stack st2;
st2.Push(cc1);
// 简化后
st2.Push({10,20});

三、静态成员变量

// 静态计数器
class MyClass {
public:MyClass() {++_instanceCount;}MyClass(const MyClass& other) {++_instanceCount;}~MyClass() {--_instanceCount;}// 没有this指针,只能访问静态成员static int getInstanceCount() {return _instanceCount;}private:int _i1 = 1;int _i2 = 1;static int _instanceCount;
};// 定义
int MyClass::_instanceCount = 0;MyClass mctest() {MyClass mc4;return mc4;
}int main(){MyClass mc1;cout << "sizeof(mc1) = " << sizeof(mc1) << endl;cout << "_instanceCount = " << MyClass::getInstanceCount() << endl;MyClass mc2(mc1);MyClass mc3 = mc2;mctest();cout << "_instanceCount = " << MyClass::getInstanceCount() << endl;MyClass obj = mctest();cout << "_instanceCount = " << MyClass::getInstanceCount() << endl;return 0;
}

结果为

sizeof(mc1) = 8
_instanceCount = 1
_instanceCount = 3
_instanceCount = 4

【练习】
在这里插入图片描述

解答:

#include <iostream>
using namespace std;class Sum {
public:Sum() {_ret += _i;++_i;}static int GetRet() {return _ret;}private:static int _i;static int _ret;
};int Sum::_i = 1;
int Sum::_ret = 0;int main() {Sum arr[100];cout << "1至100依次的加和是:" << Sum::GetRet() << endl;return 0;
}

四、友元

(1)友元函数
具体用例详见专栏里【240414 类和对象】文章中的【二、日期类:5. 流插入、流提取】部分
(2)友元类
单向,不具有交换性,不能传递,不能继承


class Time {//声明Date类是Time类的友元friend class Date;
public://...
private:int _h;int _m;int _s;//...
};class Date {
public:Date(int h, int m, int s) {_t._h = h;_t._m = m;_t._s = s;}//...
private:Time _t;//...
};

五、内部类

内部类就是外部类的友元类
B天生是A的友元

class A {
public:class B {public:B() {}void funcB() {}private:int _b1;int _b2;};A() {}void funcA() {}
private:int _a;
};
A aa;
cout << "sizeof(A) = " << sizeof(aa) << endl;A::B bb;
cout << "sizeof(B) = " << sizeof(bb) << endl;

结果:
sizeof(A) = 4
sizeof(B) = 8

B是与A平行的独立类,仅仅只受类域限制

将第三部分的【练习】题改写成内部类

class Solution {
private:class Sum {public:Sum() {_ret += _i;++_i;}static int getRet() {return _ret;}private:static int _i;static int _ret;};public:int sum_solution(int n) {Sum* arr = new Sum[n];int result = Sum::getRet();delete[] arr;return result;}
};int Solution::Sum::_i = 1;
int Solution::Sum::_ret = 0;

main 函数:

Solution sol;
cout<< "1至100依次的加和是:" << sol.sum_solution(100) << endl;

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com