类和对象(下)

文章详细介绍了C++中类的构造函数初始化列表的重要性,特别是对于const和引用成员的初始化。还讨论了静态成员变量的特性,它们属于类而非对象,并且必须在类外初始化。友元函数和友元类的概念被提出,解释了为何需要友元以及如何使用。此外,内部类和匿名对象的概念也被提及,前者允许访问外部类的私有成员,后者在作用域内短暂存在。最后,文章提到了拷贝构造时的编译器优化。
摘要由CSDN通过智能技术生成

构造函数初始化列表

我们创建一个类,借助类的构造函数去初始化数据,其实这不是真正的初始化,因为真正的初始化只会有一次,而构造函数里面可以多次赋值,最重要的是有一些类型的数据,构造函数内是无法完成初始化的,例如const修饰的变量,引用类型。

class A {
public:
	A() {
		a = 10;
		b = a;

	}
private:
	const int a;
	const int& b;
};
int main() {
	A a1;
	return 0;
}

在这里插入图片描述

显然这种情况构造函数是无法解决的,那么之前C++是怎么解决这种问题的呢?其实构造函数有一个真正初始化数据的地方,叫做初始化列表。

class A {
public:
	A()
		:a(10)
		, b(a)
	{

	}
private:
	const int a;
	const int& b;
};
int main() {
	A a1;
	return 0;
}

在这里插入图片描述

  • 每个成员变量在初始化列表只能出现一次。
  • 引用成员变量,const成员变量,自定义类型(并且需要传值的构造函数),必须放到初始化列表初始化。
  • 尽量使用初始化列表初始化。
  • 初始化列表初始化的顺序是成员变量定义的顺序。
class A
{
public:
 A(int a)
 :_a(a)
 {}
private:
 int _a;
};
class B
{
public:
 B(int a, int ref)
 :_aobj(a)
 ,_ref(ref)
 ,_n(10)
 {}
private:
 A _aobj;  // 没有默认构造函数
 int& _ref;  // 引用
 const int _n; // const 
};

static成员

类的static修饰的成员变量被称为静态变量,其实是不属于某个对象的,它是属于类的。

class A {
public:
	A() {
		ret++;//创建一个类就统计一次
	}
	static int getret() {	//静态成员函数里面只能存在静态成员变量
		return ret;
	}
private:
	static int ret;	//静态成员变量
};

int A::ret = 0;//类里面的静态成员变量只能在类外面初始化,C++规定

int main() {
	A a1;
	A a2;
	A a3;
	A a4;
	cout << A::getret() << endl;//静态成员函数可以直接访问
	cout << a1.getret() << endl;//每个对象都能访问到属于类的成员变量
	cout << a2.getret() << endl;
	cout << a3.getret() << endl;
	return 0;
}

特性:

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

友元

友元函数

现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

class Date
{
	//友元函数声明方式,关键字friend
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 2000, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& out, const Date& d)
{
	out << d._year << "年" << d._month << "月" << d._day<<"日"<<endl;
	return out;
}
istream& operator>>(istream& in, Date& d)
{
	in >> d._year >> d._month >> d._day;
	return in;
}
int main()
{
	Date d;
	cin >> d;
	cout << d << endl;
	return 0;
}

友元类

友元类的关系是单向的,友元类的关系不能传递,如果C是B的友元, B是A的友元,则不能说明C时A的友元。


class A {
//友元类的声明方式
	friend class B;
public:
	A()
		:a(1)
		,b(2)
	{

	}
private:
	int a;
	int b;
};

class B {
public:
	B()
		:a(10)
		,b(20)
	{

	}
	void show() {
		cout << a << endl;
		cout << b << endl;
		cout << a1.a << endl;//只有B类可以访问A类,A类不能访问B类
		cout << a1.b << endl;

	}
private:
	int a;
	int b;
	A a1;
};
int main()
{
	B bb;
	bb.show();
	return 0;
}

在这里插入图片描述

内部类

内部类是指一个类声明在另一个类里面,内部类是一个独立的类,不属于外部类,外部类天生就是内部类的友元类,可以访问外部类的成员变量,但是内部类不是外部类的友元类,内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

class A {
public:
	A()
		:a(10)
	{

	}
	class B {
	public:
		B()
			:bb(30)
		{

		}
		void show(const A& a1) {
			cout << k << endl;
			cout << a1.a << endl;
		}
	private:
		
		int bb;
	};
private:
	int a;
	static int k;
};
int A::k = 11;
int main() {
	A a;
	A::B b1;
	b1.show(a);
	return 0;
}

在这里插入图片描述

匿名对象

class A {
public:
	A() {
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
private:

};
int main() {

	A();//匿名对象、作用域只在这一行

	return 0;
}

在这里插入图片描述

拷贝对象时的编译器优化


class A {
public:
	A(int n) 
		:a(n)
	{
		
	}
	
private:
	int a;
};
void fun1(A a) {

}
void fun2(const A& a) {

}
int main() {
	A a = 1;//这是一个类型转换,先临时构造一个A类型的临时变量,1赋值给临时变量,然后临时变量拷贝构造给a
	//所以会调用一个构造和一个拷贝构造,但是编译器会直接优化为一个构造函数
	
	fun1(a);//没有优化,编译器优化只会在一个连续的指令
	fun1(1);//构造函数+拷贝构造-》优化为直接构造
	fun1(A(1));//构造函数+拷贝构造-》优化为直接构造

	//引用类型没有优化
	fun2(a);
	fun2(1);
	fun2(A(1));


	return 0;
}

类和对象就给大家介绍到这里,如果对您有所帮助,留一个赞吧!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值