C++ -4- 类和对象(下)

1.初始化列表

什么是初始化列表?

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟 一个放在括号中的初始值或表达式。

例如:

class Date
{
public:
	Date(int year, int month, int day)
    	 : _year(year)//以冒号开始
     	, _month(month)//逗号分隔
     	, _day(day)//括号中为初始值
 		{}
private:
	int _year;
	int _month;
	int _day;
};

初始化列表的 意义及使用

在这里插入图片描述
在这里插入图片描述
(之所以没有默认生成构造函数是因为——默认生成的构造函数对内置类型不处理,但const 变量只有一次被定义的机会,必须要初始化)

  1. 不管哪个对象调用构造函数,初始化列表是它所有成员变量定义的地方
  2. 不管是否在初始化列表里有写,编译器每个变量都会在初始化列表被初始化
  3. 如果 const 变量有缺省值,只有当其他任何地方都没有给初始化值的时候才会用这个缺省值,即没给值才用缺省值
  • 注意:
  1. 每个成员只能初始化 一次
  2. 三类 必须初始化 的类型:
    • const
    • &引用
    • 没有默认构造函数的自定义类型
class Round
{
public:
	Round(int a)//这个不是默认构造函数,默认构造函数时不传参的!!
		:_a(a)
	{}

private:
	int _a;
};

class Bottle
{
public:
	Bottle(int a, int ref)
		:_rd(a)
		, _b(ref)
		, _n(13)
	{}

private:
	Round _rd;  // 没有默认构造函数
	int& _b;  // 引用
	const int _n; // const 
};

  1. 初始化的顺序是类中成员变量定义的顺序
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();
}

output:-1  随机值
  1. 建议尽量使用初始化列表

2.explicit关键字

单参数构造函数(C++98)

分析一段代码:

class A
{
public:
	A(int a)//单参数构造函数
		:_a1(a)
	{
		cout << "A(int a)" << endl;
	}

	A(const A& aa)//拷贝构造函数
		:_a1(aa._a1)
	{
		cout << "A(const A& aa)" << endl;
	}

private:
	int _a1;
	int _a2;
};

void Testexplicit()
{
	A aa1(1);
	A aa2 = 1;

	A& variable = 13;
    const A& variable = 13;
}

int main()
{
	Testexplicit();
	return 0;
}

在这里插入图片描述

🔊 explicit 不允许隐式类型转换:
在这里插入图片描述

多参数的构造函数(C++11)(了解)

class A
{
public:
	A(int a1, int a2)//多参数构造函数
		:_a1(a1)
		, _a2(a2)
	{}

private:
	int _a1;
	int _a2;
};

void Testexplicit()
{
	A aa3(1, 2);
	A aa4 = { 1,2 };
}

3.static静态成员

  • 如何统计 类的对象的个数

基本思路:创建 类的对象一定回去调用 构造函数 或者 拷贝构造函数

  1. 定义全局变量统计个数?
  • 代码:
int count = 0;
class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

private:
	int _a1;
	int _a2;
};

void TestStatic()
{
	A a1, a2, a3, a4;
	cout << count << endl;
}
  • 问题:
  • 变量名冲突

报错:变量名 count 与 std 库发生冲突

error C2872: “count”: 不明确的符号
message : 可能是“int count”或 “iterator_traits<_Iter>::difference_type std::count(const _InIt,const _InIt,const _Ty &)”

所以,最好不要全局展开std

  • 容易出纰漏
    在这里插入图片描述

静态成员变量与静态成员函数

静态成员变量

  1. ✅静态成员变量:属于所有对象
  • 静态成员变量的声明和初始化:
class A
{
	static int count;//声明
};
int A::count = 0;//定义初始化

注意:静态成员变量声明处不能给缺省值,缺省值时给构造函数初始化用的,作用于非静态成员变量

  • 静态成员变量的访问:(以上述代码为例)

①当 静态成员变量 是 public

void TestStatic()
{
	A a1;
	a1.count;
	A::count;
	A* ptr = nullptr;  
	ptr->count;
}
  • 对象.count:A a1;a1.count;——创建对象,通过对象访问成员变量
  • A::count;
  • A* ptr = nullptr; ptr->count;

② 通过写函数访问

class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

	int Getcount()
	{
		return count;
	}

private:
	int _a1;
	int _a2;

	static int count;//声明
};

int A::count = 0;//定义初始化

void TestStatic()
{
	A a1;
	cout << a1.Getcount() << endl;
}

静态成员函数

void TestStatic()
{
	A a1;
	cout << a1.Getcount() << endl;
}

👆为了调用这个函数专门要创建一个对象?→如何改进?→『 静态成员函数

  • 什么是 静态成员函数:(示例)
static int Getcount()
{
	return count;
}
  • 如何调用静态成员函数:
    A::Getcount();

(完整示例:↓)

class A
{
public:
	A()//构造函数
	{
		++count;
	}
	A(const A& aa)//拷贝构造函数
	{
		++count;
	}

	static int Getcount()
	{
		return count;
	}

private:
	int _a1;
	int _a2;

	static int count;//声明
};

int A::count = 0;//定义初始化

void TestStatic()
{
	A array[13];
	cout << A::Getcount() << endl;
}

ps.A array[13]; 自定义类型的数组,会自动调用13次构造函数。

  • 静态函数变量的特点:
    静态成员函数没有 this 指针,因此 不能访问非静态成员

4.匿名对象

  • 什么是匿名对象:
class A{};
A();//匿名对象
  • 匿名对象的特点:生命周期只在这一行

ps.临时变量和匿名对象都具有 常性


5.友元

友元分为 友元函数友元类,由于友元 破坏了封装 ,建议能不用就不用。

友元函数

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在 类的内部声明,声明时需要加friend关键字。

示例:

class Date
{
public:
	//流插入
	//函数声明
	friend void operator<<(ostream& out, const Date& d);
	
private:
	int _year;
	int _month;
	int _day;
};

//函数定义
void operator<<(ostream& out, const Date& d)
{
	out << d._year << "/" << d._month << "/" << d._day << endl;
	//友元函数可以直接访问类的私有成员
}

//函数调用:
cout << d1; 👉 operator<<(cout,d1);

注意:

  • 友元函数可访问类的私有和保护成员,但不是类的成员函数
  • 友元函数不能用const修饰
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制
  • 一个函数可以是多个类的友元函数

友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。 友元关系是单向的,不具有交换性。

在这里插入图片描述


6.内部类(C++很少用)

  • 概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个 独立(空间独立)的类,它不属于外部类!
  • 注意:内部类就是外部类的友元类,但是外部类不是内部类的友元。
  • 特性:
    1. 内部类可以定义在外部类的public、protected、private都是可以的。
    2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
    3. sizeof(外部类)=外部类,和内部类没有任何关系。内部类是独立的!

内部类可以看作是外部类的友元类,只是受外部类的类域限制。

class A
{
public:
	class B //内部类
	{
	public:
		void foo(const A& a)
		{
			cout << k << endl;
			cout << a.h << endl;
		}
	};


private:
	static int k;
	int h;
};

int A::k = 1;
int main()
{
	A::B b;//类B受外部类A的类域限制
	b.foo(A());
	return 0;
}

7.拷贝对象时的一些编译器优化

1. 构造+拷贝 → 优化为直接构造
当构造和拷贝都在一个表达式里时才能优化:

  • 不在一个表达式:
    在这里插入图片描述

  • 在一个表达式:
    在这里插入图片描述

2. 传引用传参 → 不优化,没有拷贝

3. 传值返回 → 不优化(如下代码,构造和拷贝不能结合起来)

A func()
{
	A aa;//构造   “构造”
	return aa;//返回一份临时拷贝 “拷贝”
}

4.返回值接收:拷贝+拷贝 → 优化成一个拷贝

class A{};

A func()
{
	A aa;//构造   “构造”
	return aa;//返回一份临时拷贝 “拷贝”
}

int main()
{
	/*func(A());*/

	A aa1 = func();//拷贝接收
	//func()“拷贝”+aa1"拷贝构造" → “拷贝”+“拷贝”

	//如果写成:
	A aa2;
	aa2 = func();//这样写不优化
	return 0;
}

5. 返回匿名对象

class A{};

A func()
{
	return A();
}

构造匿名对象 A() → “构造”
返回一个自定义对象,生成一份临时拷贝 → “拷贝”
构造+拷贝 → 优化为直接构造

sum.提高效率:
1.接收返回值对象,尽量用拷贝接收(4.)
2.返回值尽量用匿名对象(5.)
3.传参尽量用引用(2.)


END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

畋坪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值