【C++基础八】类和对象—末(初始化列表、友元和匿名对象)

1.初始化列表

构造函数中,为一个成员赋值,只能说对此成员赋初始值,不能称之为初始化,初始化列表才是真正初始化成员变量的地方

1.1初始化列表的使用

例:

class Date
{
public:
	Date(int year, int month, int day)
   		: _year(year)
   		, _month(month)
   		, _day(day)
	{
		_year++;
		_day--;
		_month = month;
	}
private:
	int _year;
	int _month;
	int _day;
};

有些变量在初始化时必须对它赋值

  • const成员变量

  • 引用成员变量

  • 没有默认构造的自定义类型成员

然而在构造函数的函数体中的赋值行为不是对变量的初始化,在使用上述类型时会报错,所以必须用初始化列表

class B
{
public:
	B(int a, int ref)
		:_n(10)
		,_ref(ref)
		,_obj(a)
	{}
private:
	const int _n; // const修饰成员 
	int& _ref;  // 引用成员
	A _aobj;  // 没有默认构造函数的自定义类型
};

对于自定义成员来说,不管有没有显示写初始化列表,它都会优先使用初始化列表初始化,所以在之后尽量使用初始化列表进行初始化

1.2初始化列表的细节

初始化列表中,初始化变量的顺序是变量在类中声明的顺序

class A
{
public:
    A(int i)
       :_a1(i)
       ,_a2(_a1)
   {}
private:
    int _a2;
    int _a1;
};

int main() 
{
    A temp(3);
}

此时,_a2会先初始化,_a1再初始化
因为_a2初始化时_a1还是随机值,所以_a2就被初始化成了随机值,而_a1会被初始化为3

class A
{
public:
    A(int i)//没有显示传参,就用缺省值初始化
       :_a1(i)
       ,_a2(i)
   {}
private:
    int _a2 = 1;
    int _a1 = 2;
};

int main()
{
	A temp();
}

当用户没有显示传参进行初始化时,编译器会用成员变量的缺省值初始化
当用户显示传参时,使用用户传的值初始化

2.static成员

  • 声明为static的类成员称为类的静态成员
  • 用static修饰的成员变量称之为静态成员变量
  • 用static修饰的成员函数称之为静态成员函数
  • 静态成员变量一定要在类外进行初始化

static成员的特性:

  1. 静态成员为所有类对象共享,放在静态区
  2. 静态成员变量必须在类外定义,类中只是声明
  3. 类静态成员可用类名::静态成员对象.静态成员访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员受访问限定符的限制
class B
{
public:
	 static int Add(int x,int y);//没有this指针,无法访问类中成员
	 static int a;//在类中声明
};
int B::a = 10;//在类外定义

3.友元

3.1友元函数

一个函数定义在类外,但又想访问类中的私有成员,只能将这个私有成员改成公有后再访问,但这种操作就破坏了类的封装

引入友元:

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

class Date
{
	 friend int Add(int x,int y);//友元函数的声明
public:
	 Date(int year = 1999, int month = 9, int day = 9)
	 	: _year(year)
	 	, _month(month)
	 	, _day(day)
	 {}
private:
	 int _year;
	 int _month;
	 int _day;
};

int Add(int x,int y)//友元函数的定义
{
	x += _year;
	y += _month - _day;
	return x + y;
}

友元函数特点:

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

3.2友元类

除了有友元函数可以访问类私有成员外,声明友元类也可以达到一样的效果,而内部类就是友元类的典型
内部类是一个定义在另一个类内部的类,内部类是一个独立的类,不属于外部类,不能通过外部类的对象访问内部类的成员(外部类对内部类,没有任何优越的访问权限)
内部类是外部类的友元:内部类可以通过外部类的对象参数访问外部类的所有成员
外部类不是内部类的友元

class A
{
private:
	 static int k;
	 int h;
public:
	 class B // B天生就是A的友元
	 {
	 public:
		 void foo(const A& a)
		 {
			 cout << k << endl;//无报错
			 cout << a.h << endl;//无报错
		 }
	 };
};

4.类的匿名对象

class Date
{
public:
 Date(int year = 1900, int month = 1, int day = 1)
	 : _year(year)
	 , _month(month)
	 , _day(day)
	 {}
private:
	 int _year;
	 int _month;
	 int _day;
};

int main()
{
	Date d = Date(2023,8,1);//Date(2023,8,1)就是匿名对象
	return 0;
}

特点:

  1. 生命周期只有一行
  2. 只有类名,没有变量名,在初始化或销毁时自动调用构造或析构函数

当定义第一个变量只是为了调用类中的一个函数,并且调用完后此变量不会再被使用,此时可用匿名对象

5.explicit

int main()
{
    A a(1);//构造函数初始化对象a
    A b = 1;//对象d没有被初始化,直接被赋值,产生隐式类型转换:int类型转换为A类型
    return 0;
}

内置类型int对于自定义类型A的类型转换,通过构造函数产生一个类型为A的临时变量,再通过拷贝构造把临时变量传给b
但是程序运行发现,只进行了两次构造,并没有拷贝构造,说明C++对于自定义类型产生临时变量,编译器会做优化

#include<iostream>
using namespace std;
v
class A
{
public:
    explicit A(int n)//构造
        :_a(n)
    {
        cout << "A(int n)" << endl;
    }
    A(A& d)//拷贝构造
    {
        cout << "A(A&d)" << endl;
    }
private:
    int _a;
};
int main()
{
    A a(1);//构造函数
    A b = 1;//隐式类型转换 加入关键字explicit会报错
    return 0;
}

为了防止隐式类型转换发生,所以在构造函数前加入关键字explicit

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值