C++初阶(5)—— 构造函数的初始化方式、static成员、友元、重载<<与>>

在C++初阶(4)中,我们具体实现了Date日期类。今天我想继续往下讲C++的其他一些语法知识点。

一、构造函数的初始化方式
使用构造函数对对象进行初始化时,有两种方式:
(1)函数体内实现

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

(2)使用初始化列表初始化

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

但注意,有三种成员变量必须使用初始化列表初始化。

  1. const变量
  2. 引用

初始化列表是成员变量的定义阶段,而const和引用类型的变量必须在定义后立马初始化,所以必须放在初始化列表初始化

3.没有默认构造函数的自定义类型变量
举例说明:

class A
{
	//没有默认构造函数
};
class Date
{
public:
	Date(int year, int month, int day)
		:_n(10)
		, _ref(year)
		, _a(1)//因此A的对象_a要放在初始化列表中初始化
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;

	const int n;
	int& ref;
	A _a;
};

另外,成员变量在初始化列表中的初始化顺序类中的声明次序决定,与其在初始化列表中的先后顺序无关
因此建议:在类中声明的成员变量的顺序与初始化列表中的顺序保持一致
举例说明:

//下面程序的输出结果是?  D
class A
{
private:
	int _a2;
	int _a1;
public:
	//先初始化_a2,为随机值   再初始化_a1,为1
	A(int a)
		:_a1(a)
		, _a2(_a1)
	{}
	void Print()
	{
		cout << _a1 << "" << _a2 << endl;
	}
};
int main()
{
	A.aa(1);
	aa.Print();
	return 0;
}
A.1  1   B.程序崩溃  C.编译不通过   D.1  随机值

二、Static
·static成员变量

class A
{
private:
	static int n;//n存在于静态区,属于整个类也属于类的所有对象
	//静态成员不能在构造函数里初始化
};
int A::_n = 0;//在类外单独初始化,前面不加static
			  //注意不能在main函数中初始化

static变量存在于静态区,属于整个类,不属于某个单独的对象。
因此静态成员不能在构造函数里初始化,要在类外单独初始化,且前面不加static

由于静态成员属于整个类,因此既可以通过类名访问,也可以通过类的某个对象访问

class Date
{
private:
	int _year;
	int _month;
	int _day;
public:
	Date(int year = 2021, int month = 8, int day = 15)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	static int n;
};
int Date::n = 2021;
int main()
{
	Date d1(2021,8,19);
	Date d2(d1);
	Date d3(d2);
	cout << Date::n << d1.n << d2.n << d3.n << endl;
	return 0;
}

·静态成员函数
静态成员函数的特点:
C++初阶(5)—— 构造函数的初始化方式、static成员、友元、重载<<与>>_第1张图片
另外,静态成员函数不能调用非静态成员函数,非静态成员函数能调用静态成员函数

举例说明:

class A
{
private:
	int a;
	static int n;
public:
	static int Get_n()
	{
		a = 1;//error!不能访问a
		return n;
	}
	//所以 如果某函数专门是为了访问静态成员,可以设计成静态函数
};

下面,我们通过一个例题,来更好地了解静态成员函数的作用
例题1:

求1+2+3+……10,不能使用乘除法,for while if wlse switch case

class Add
{
public:
	Add()
	{
		sum += n;
		++n;
	}
	Add(const Add& a)
	{
		++n;
	}
	void Print()
	{
		cout << Add::sum << endl;
	}
private:
	static int n;
	static int sum;
}; 

int Add::n = 1;
int Add::sum = 0;

int main()
{
	Add aa[10];//创建对象数组,相当于调用10次构造函数
	aa[0].Print();
	return 0;
}

三、友元
·友元函数

声明形式:
friend 返回类型 函数名(参数列表)
特点:

  1. 友元函数可以访问类的私有和保护成员,但并不是类的成员函数
  2. 友元函数不能用const修饰
  3. 友元函数不受类的访问限定符控制,可以在类的任何地方声明
  4. 一个函数可以同时是多个类的友元函数
  5. 友元函数的嗲用与普通函数的调用和原理相同

我们通过重载<<和>>来举例说明:
重载<<时,要实现连续输出,必须是cout<<变量的形式。如果设计成普通成员函数,第一个参数默认为this指针,调用时只能写成变量>>cout*,就没法连续输出了
另外,函数的返回类型应是ostream类的引用

重载>>同理。

class Date
{
private:
	int _year;
	int _month;
	int _day;
public:
	Date(int year = 0, int month = 0, int day = 0)
	{
		this->_year = year;
		this->_month = month;
		this->_day = day;
	}
	friend ostream& operator<<(ostream& out, const Date& d);
	friend istream& operator>>(istream& in, Date& d);
};

ostream& operator<<(ostream& out, const Date& d)//注意这里d也要取引用
{
	//这里设计成友元而不设计成成员函数。
	//因为成员函数的第一个参数必定是隐藏的指针,这样就没法把cout写在左边了
	//为了实现cout<
	out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
	return out;
}
istream& operator>>(istream& in, Date& d)//注意这里d也要取引用
{
	in >> d._year >> d._month >> d._day;
	return in;
}

int main()
{
	Date d1;
	Date d2(2021, 5, 25);
	cin >> d1 >> d2;
	cout << d1 << d2;
	return 0;
}

·友元类
特点:

  1. 友元关系是单向的,不具有交换性
    如A是B的友元类,则A中所有的成员函数都是B的友元函数,都可以访问B中的非公有成员。但反之就不行
  2. 友元关系不能传递
    B是A的友元,C是B的友元,不能说明C是A的友元

举例说明:

class Time
{
    //声明Date为Time类的友元类,可以在Date类中访问Time类的私有成员
	friend class Date;
private:
	int _hour;
	int _minute;
	int _second;
public:
	Time(int hour = 0,int minute=0,int second=0)
		:_hour(hour)
		,_minute(minute)
		,_second(second)
	{}
};

class Date
{
private:
	int _year;
	int _month;
	int _day;
	Time _t;
public:
	Date(int year=2021,int month=0,int day=0)
		: _year(year)
		,_month(month)
		,_day(day)
	{
		_t._hour = 1;
	}

	void SetTimOfDate(int hour, int minute, int second)
	{
		_t._hour = hour;
		_t._minute = minute;
		_t._second = second;
	}
};

但是要说明的是:友元是一种破坏封装的行为。因此一般情况下,不建议使用友元

你可能感兴趣的:(C++初阶,c++)