練習7.31 定義一對類X 和Y,其中X 包含一個指向 Y 的指針,而Y 包含一個類型爲 X 的對象。
class Y;
class X
{
private:
Y* p = nullptr;
};
class Y
{
private:
X p;
};
練習7.32 定義你自己的Screen 和 Window_mgr,其中clear是Window_mgr的成員,是Screen的友元。
//Screen.h
#pragma once
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Screen;
class Window_mgr {
public:
using ScreenIndex = std::vector<Screen>::size_type;
void clear(ScreenIndex i);
private:
std::vector<Screen> screens;
};
class Screen {
//friend class Window_mgr;
friend void Window_mgr::clear(std::vector<Screen>::size_type i);
public:
using pos = std::string::size_type;
Screen() = default;
Screen(const pos h, const pos w) :
height(h), width(w), contents(h*w, ' ') {}
Screen(const pos h, const pos w, const char c):
height(h), width(w), contents(h*w, c) {}
char get() const {return contents[cursor];}
char get(pos r, pos c) const { return contents[width*r+c]; }
Screen &move(pos r, pos c) { cursor = r * width + c; return *this; }
Screen &set(const char c) { contents[cursor] = c; return *this; }
Screen &set(pos r, pos col, const char ch) { contents[r*width + col] = ch; return *this; }
Screen &display(ostream &os) { do_display(os); return *this; }
const Screen &display(ostream &os) const { do_display(os); return *this; }
private:
void do_display(ostream &os)const { os << contents; }
pos cursor = 0;
pos height = 0, width = 0;
string contents;
};
void Window_mgr::clear(ScreenIndex i) {
Screen &s = screens[i];
s.contents = string(s.height * s.width, ' ');
}
PS:感覺這種寫法十分不友好,很容易導致邏輯混亂,如果不熟悉C++的程序員維護這段代碼,非常有可能導致錯誤。
練習7.33 如果我們給Screen 添加一個如下所示的size成員將發生什麼情況?如果出現了問題,請嘗試修改它。
pos Screen::size() const
{
return height * width;
}
編譯器會報錯,因爲找不到pos
的聲明。應該改爲:
Screen::pos Screen::size() const
{
return height * width;
}
練習7.34 如果我們把第256頁Screen
類的pos
的typedef
放在類的最後一行會發生什麼情況?
類中所有是用了pos
的地方都會報錯:未定義的標識符pos
類型名的定義通常出現在類的開始處,這樣就能確保所有使用該類型的成員都出現在類名的定義之後。
練習7.35 解釋下面代碼的含義,說明其中的Type
和initVal
分別使用了哪個定義。如果代碼存在錯誤,嘗試修改它。
練習7.36 下面的初始值是錯誤的,請找出問題所在並嘗試修改它。
struct X {
X (int i, int j): base(i), rem(base % j) {}
int rem, base;
};
應改爲:
struct X{
X(int i, int j): base(i), rem(base%j){}
int base, rem;
}
練習7.37 使用本節提供的Sales_data類,確定初始化下面的變量時分別使用了哪個構造函數,然後羅列出每個對象所有的數據成員的值。
Sales_data first_item(cin); // 使用 Sales_data(std::istream &is) ; 各成員值從輸入流中讀取
int main() {
Sales_data next; // 使用默認構造函數 bookNo = "", cnt = 0, revenue = 0.0
// 使用 Sales_data(std::string s = "");bookNo = "9-999-99999-9", cnt = 0, revenue = 0.0
Sales_data last("9-999-99999-9");
}
練習7.38 有些情況下我們希望提供cin
作爲接受istream&
參數的構造函數的默認實參,請聲明這樣的構造函數。
Sales_data(std::istream & = std::cin);
練習7.39 如果接受string
的構造函數和接受 istream&
的構造函數都使用默認實參,這種行爲合法嗎?如果不,爲什麼?
不合法,會造成二義性調用的錯誤。
練習7.40 從下面的抽象概念中選擇一個(或者你自己指定一個),思考這樣的類需要哪些數據成員,提供一組合理的構造函數並闡明這樣做的原因。
(a) Book (b) Data (c) Employee
(d) Vehicle (e) Object (f) Tree
//Employee.h
#include<string>
class Employee
{
public:
Employee(const std::string &s, int sly, int dpt, int wy = 0) : emNum(s), salary(sly), department(dpt), workYear(wy) {};//傳入全部參數進行構造
Employee(const Employee &oth) { *this = oth; }//拷貝構造
Employee() = default;//默認構造一個空的對象
~Employee();
private:
std::string emNum = "";
int salary = 0;
int department = 0;
int workYear = 0;
};
Employee::~Employee()
{
}