第四章:设计与声明(一)
让接口容易被正确使用,不易被误用
class Date
{
public:
Date(int month, int day, int year)
...
};
1
2
3
4
5
6
2
3
4
5
6
上述接口可能会引起客户调用的错误,即填写顺序出错:
Date d(2, 30, 2020);
Date d(30, 2, 2020);
1
2
2
进一步,可以将month,day,year封装成struct或class
struct Day
{
explicit Day(int d)
:val(d)
{}
int val;
};
struct Month
{
explicit Month(int d)
:val(d)
{}
int val;
};
struct Year
{
explicit Year(int d)
:val(d)
{}
int val;
};
class Date
{
public:
Date(const Month& m, const Day& d,const Year& y)
...
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
这样调用的时候会直接报类型不匹配:
Date m_date(Month(12),Day(20),Year(2020));//正确
Date m_date1(Day(20),Month(12),Year(2020));//错误
//error: no matching function for call to ‘Date::Date(Day, Month, Year)’
1
2
3
2
3
但是构造函数内仍需要做Day、Month和Year之间的关系以及大小限制。 STL容器的接口十分一致,size函数对各个容器都适用,不像Java中数组适用length,Lists使用size。
设计class犹如设计type
宁以pass-by-reference-to -const替换pass-by-value
优点:
- 避免额外的构造和析构函数带来的消耗,因此比较高效。
- 以by-reference方式传递参数可以避免slicing(对象切割)问题。
注意事项:
以上规则并不适用于内置类型,以及STL的迭代器和函数对象。对它们而言,pass-by-value 往往比较恰当。
bool validateStudent(Student s);
bool platoIsOK = validateStudent(plato);
1
2
2
上述过程:Student的copy构造函数被调用,以plato为蓝本初始化s。当validateStudent函数返回时,s会被销毁。因此,对此函数而言,参数的传递成本是“一次Student copy构造函数被调用 ,加上一次Student析构函数调用”。当Student类中存在多个成员变量的时候,构造和析构的次数会成倍增加。
采用bool validateStudent(const Student& s) 效率会高很多,因为没有任何新对象被创建,所以没有任何构造函数和析构函数被调用。
当一个derived class 对象以by value方式传递并视为一个base class对象, base class的copy构造函数会被调用,而“造成此对象的行为像个derived class对象”的那些特化性质全被切割,仅仅留下一个base class对象。
void printNameAndDisplay(Window w)
void printNameAndDisplay(const Window& w)
1
2
2
← 第三章:资源管理 第四章:设计与声明(二) →