《C++ Primer》5th 課後練習 第七章 類 41~50

練習7.41 使用委託構造函數重新編寫你的Sales_data 類,給每個構造函數體添加一條語句,令其一旦執行就打印一條信息。用各種可能的方式分別創建 Sales_data 對象,認真研究每次輸出的信息直到你確實理解了委託構造函數的執行順序。

//Sale_data.h
#pragma once
#include <iostream>
#include <string>
using namespace std;
struct Sales_data {
	friend istream &read(istream &is, Sales_data &item);
	friend ostream &print(ostream &os, const Sales_data &item);
	friend Sales_data add(const Sales_data &a, const Sales_data &b);

public:
	Sales_data(const string &s, const unsigned cnt, const double p) :
		bookNo(s), units_sold(cnt), revenue(cnt*p) {
		cout << "I have three para" << endl;
	}

	Sales_data():Sales_data("", 0, 0) {
		cout << "I have zero para" << endl;
	};
	Sales_data(const string &s) : Sales_data(s, 0, 0) {
		cout << "I have one para" << endl;
	}
	Sales_data(istream &is):Sales_data() {
		cout << "I have one istream para" << endl;
		double price;
		is >> this->bookNo >> this->units_sold >> price;
		this->revenue = this->units_sold * price;
	}
	string isbn()const { return this->bookNo; }
	Sales_data &combine(const Sales_data &other);

private:
	inline double avg_price() const;
	string bookNo;
	unsigned units_sold = 0;
	double revenue = 0.0;
};
inline
double Sales_data::avg_price() const
{
	return units_sold ? revenue / units_sold : 0;
}
istream &read(istream &is, Sales_data &item);
ostream &print(ostream &os, const Sales_data &item);
Sales_data add(const Sales_data &a, const Sales_data &b);
//Sale_data.cpp
#include"Sale_data.h"

//Sales_data::Sales_data(istream &is) {
//	read(is, *this);
//}
Sales_data &Sales_data::combine(const Sales_data &other) {
	this->units_sold += other.units_sold;
	this->revenue += other.revenue;
	return *this;
}
istream &read(istream &is, Sales_data &item) {
	double price;
	is >> item.bookNo >> item.units_sold >> price;
	item.revenue = item.units_sold * price;
	return is;
}
ostream &print(ostream &os, const Sales_data &item) {
	os << item.bookNo << " " << item.units_sold << " " << item.revenue;
	return os;
}
Sales_data add(const Sales_data &a, const Sales_data &b) {
	Sales_data sum = a;
	sum.combine(b);
	return sum;
}
#include "Sale_data.h"
int main(int argc, char **argv)
{
	Sales_data a("111", 0, 0);
	cout << endl;
	Sales_data b;
	cout << endl;
	Sales_data c("222");
	cout << endl;
	Sales_data d(cin);
	return 0;
}

運行結果:

I have three para

I have three para
I have zero para

I have three para
I have one para

I have three para
I have zero para
I have one istream para
123 1 2

如果有委託構造函數,則先執行委託構造函數,將所有遞歸的委託構造函數執行完之後再執行自己。

練習7.42 對於你在練習7.40中編寫的類,確定哪些構造函數可以使用委託。如果可以的話,編寫委託構造函數。如果不可以,從抽象概念列表中重新選擇一個你認爲可以使用委託構造函數的,爲挑選出的這個概念編寫類定義。

#pragma once
//Employee.h
#include<string>
class Employee
{
public:
	Employee() = default;//默認構造一個空的對象
	Employee(const std::string &s, int sly, int dpt, int wy = 0) : emNum(s), salary(sly), department(dpt), workYear(wy) {};//傳入全部參數進行構造
	Employee(const Employee &oth):Employee() //委託構造
					{ *this = oth; }//拷貝構造

	~Employee();
private:
	std::string emNum = "";
	int salary = 0;
	int department = 0;
	int workYear = 0;
};
Employee::~Employee()
{

}

練習7.43 假定有一個名爲 NoDefault 的類,它有一個接受 int 的構造函數,但是沒有默認構造函數。定義類 C,C 有一個 NoDefault 類型的成員,定義C 的默認構造函數。

class NoDefault{
public:
	NoDefault(int c){}
}
class C{
public:
    C():def(0){}
private:
    Nodefault d;
}

練習7.44 下面這條聲明合法嗎?如果不,爲什麼?

vector<NoDefault> vec(10);

不合法,NoDefault類沒有默認

練習7.45 如果在上一個練習中定義的vector的元素類型是C,則聲明合法嗎?爲什麼?

合法,C有默認構造函數。

練習7.46 下面哪些論斷是不正確的?爲什麼?

(a) 一個類必須至少提供一個構造函數。
(b) 默認構造函數是參數列表爲空的構造函數。
© 如果對於類來說不存在有意義的默認值,則類不應該提供默認構造函數。
(d) 如果類沒有定義默認構造函數,則編譯器將爲其生成一個並把每個數據成員初始化成相應類型的默認值。

(a)錯誤,因爲如果沒有顯式地聲明構造函數,那麼編譯器會幫助我們隱式地定義一個默認構造函數,稱爲合成的默認構造函數。

(b)錯誤,也可以是,爲每個參數都提供了默認值的構造函數。

(c)錯誤,用該類型創建容器或直接聲明非靜態變量時,若沒有默認構造函數,將產生錯誤。

(d)錯誤,當類沒有構造函數時,編譯器纔會創建默認構造函數。

練習7.47 說明接受一個string 參數的Sales_data構造函數是否應該是explicit的,並解釋這樣做的優缺點。

我覺得應該是explicit的。

優點:

  • 避免了造成使用者發生一些低級錯誤。

缺點:

  • 導致構造函數在使用時不那麼靈活。

練習7.48 假定Sales_data 的構造函數不是explicit的,則下述定義將執行什麼樣的操作?

string null_isbn("9-999-9999-9");
Sales_data item1(null_isbn);
Sales_data item2("9-999-99999-9");

這些定義跟exlicit無關吧?

練習7.49 對於combine 函數的三種不同聲明,當我們調用i.combine(s) 時分別發生什麼情況?其中 i 是一個 Sales_data,而 s 是一個string對象。

(a) Sales_data &combine(Sales_data); // ok
(b) Sales_data &combine(Sales_data&); // error C2664: 無法將參數 1 從“std::string”轉換爲“Sales_data &”	
(c) Sales_data &combine(const Sales_data&) const; // 該成員函數是const 的,意味着不能改變對象。而 combine函數的本意就是要改變對象

練習7.50 確定在你的Person 類中是否有一些構造函數應該是 explicit 的。

explicit Person(istream &is) { read(is, *this); }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章