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;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值