深入了解构造函数

struct Sales_data
{
	friend Sales_data add(const Sales_data&, const Sales_data&);
	friend std::istream &read(std::istream&, Sales_data&);
	friend std::ostream &print(std::ostream&, const Sales_data&);


public:
	//定义构造函数,对类对象进行初始化
	Sales_data() = default;//默认构造函数,意思是我们需要默认的行为,等同于之前使用的合成默认构造函数
	Sales_data(const std::string &s) :bookNo(s) {}//冒号以及冒号和花括号之间的代码叫作构造函数初始值列表,负责为新创建的对象的一个或几个数据成员赋初值,每个名字后面跟着用括号扩起来的初始值
	Sales_data(const std::string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(p*n) {}//当某个数据成员被构造函数初始值列表忽略时,他将以与合成默认构造函数相同的方式隐式初始化
	Sales_data(std::istream &);//类外构造函数的声明,定义在类的外部
							   //尽管构造函数的参数列表为空,但是由于执行了构造函数体,所以对象的成员仍然能被初始化;通过默认初始化,用类内初始值进行初始化
	
	std::string isbn() const
	{
		return bookNo;
	}
	Sales_data& combine(const Sales_data&);//此为一个引用函数,返回值是一个对象的所有成员值,函数的类型以及返回值类型是 Sales_data& 类型
	
private:
	double avg_price() const
	{
		return units_sold ? revenue / units_sold : 0;
	}
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};

//类的外部定义构造函数
Sales_data::Sales_data(std::istream &is)
{
	read(is, *this);
}

//再探构造函数
//1.初始化的另外一种方式
Sales_data::Sales_data(const string& s, unsigned cnt, double price) {
	bookNo = s;
	units_sold = cnt;
	revenue = cnt * price;
}
//可能出现的错误
class ConstRef
{
public:
	ConstRef(int ii);


private:
	int i;
	const int ci;
	int& ri;


};


ConstRef::ConstRef(int ii)
{
	i = ii;
	//ci = ii;error:不能给const赋值
	//ri = i;error:ri没被初始化
}
//综上所述,通常情况下都用初始值列表进行初始化,一般不会出错。。。如果成员是const、引用或者属于某种未提供默认构造函数的类类型,务必不能用赋值操作进行初始化




//2、成员初始化的顺序
class X {
	int i;
	int j;
public:
	//X(int val): j(val), i(j){};error:理由如下
	X(int val) :j(val), i(val){}
};
//成员的初始化顺序与成员在类中定义出现的顺序一致。所以上述程序先初始化i,再初始化j。。。所以程序会出错
//但是初始值列表只说明初始化成员的值,而不规定顺序.
//所以尽量在构造函数的参数列表中设置好完整的初始值,而不需要使用同一个对象中的不同成员,避免出现上述错误




//委托构造函数//
class sales_data {
public:
	sales_data(std::string s, unsigned cnt, double price):
		bookNo(s), units_sold(cnt), revenue(cnt*price){}
	sales_data():sales_data("", 0, 0){}		//此为默认构造函数;<=> sales_data() = default; 这么写意思是委托给三参数的构造函数
	sales_data(std::string s):sales_data(s,0, 0){}	//调用时:<=>sales_data("hello");<=>sales_data("hello", 0, 0);	用前者调用,实则用后者初始化
	sales_data(std::string &is):sales_data(){read(is, *this) }	//现委托给了默认构造函数sales_data(),默认函数又将其委托给三参数构造函数,初始化的值从编译器中输入


private:
	std::string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};


//类的静态成员//
class Account {
public:
	void calculate() { amount += amount * interestRate;}
	static double rate() { return interestRate; }
	static void rate(double);
private:
	std::string owner;
	double amount;
	static double interestRate;
	static double initRate();
};


double Account::interestRate = initRate();//对静态成员进行初始化,和全局变量一样,必须出现在任何函数之外
//虽然initRate是私有的,但和其他成员的定义是一样的,可以访问类的私有成员。


void Account::rate(double newRate)
{
	interestRate = newRate;
}//若在函数体外定义静态成员函数,则static只能出现在函数体内的声明,定义时不可以再出现static。
//类的静态成员存在于任何对象之外,对象中不包含任何与静态数据成员有关的数据。正如例子中所示,静态数据成员被所有的Account对象共享
//因此,静态成员函数不与任何对象绑定在一起,也不包含this指针。
//所以,静态成员函数不能声明成const的,也不能在static函数体内使用this指针。




//静态成员的类内初始化//
class account {
public:
	static double rate() { return interestRate; }
	static void rae(double);
private:
	static constexpr int period = 30;
	static double interestRate;
	double daily_tbl[period];
};
//即使一个常量静态数据成员在类内部被初始化了,通常还得在类的外部定义一下
constexpr int account::period;


//静态小花园能用于某些场景,而普通成员则不可以
class Bar {
public:
	//此时Bar还没有定义完全,所以Bar类型是一种不完全类型
private:
	static Bar mem1;
	Bar *mem2;
	//Bar mem3;  error:数据成员必须是完全类型
};
//静态成员的类型可以是他所属的类类型,而非静态数据成员收到限制,只能声明成它所属类的指针或引用
//另一个区别是:可以使用静态成员作为默认实参

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值