如何写出高效C++(设计与声明)
2016-08-13 11:19
253 查看
18.让接口容易被正确使用不易被误用
(1)许多客户端错误可以因为导入新类型而获得预防(explicit的作用是防止隐式转换)
例如Date(int month,int day,int year);乍看正确,其实不然
解决方案是构造如下三类
struct Day
struct Month
struct Year
(2)预防客户错误的另一个方法是,限制类型内什么事可做,什么事不能做。
使自己的类型和内置类型基本一致
(3)关于tr1::shared_ptr指针
毫无疑问的是这个指针比原始指针大且慢,而且使用辅助动态内存,但是在许多应用中这些额外的执行成本并不显著,但是它"降低客户错误的成效"十分显著,所以遇到与内存有关的指针操作的时候大家可以考虑使用它。
19.设计class犹如设计type
20.宁以pass-by-reference-to-const替换pass-by-value(以传常引用调用替换传值调用)
关于pass-by-value的弊端:传值调用实际上函数参数是以实际实参的复件为初值,而调用端所获得的亦是函数返回值的一个复件,这些复件是由对象的copy构造函数产出,这可能使pass-by-value成为昂贵的(费时)的操作。
bool validateStudent(Student s);
bool validateStudent(const Student &s);
对于内置类型,STL的迭代器和函数对象而言其实pass-by-value的效率更高。
21.必须返回对象时别妄想返回reference
所谓reference只是名称,代表的是某个既有对象。
关于必须返回对象时的正确写法:
inline const Rational operator* (const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.n* rhs.n,lhs.d* rhs.d);
}
(1)绝不要返回pointer或reference指向一个local stack对象
(2)绝不要返回reference指向一个heap-allocated对象
(3)绝不要返回一个pointer或reference指向一个local static对象而有可能同时需要多个这样的对象。
22.将成员变量声明为private
好处:可以赋予客户访问数据的一致性,可细微划分访问控制,允诺约束条件获得保证,并提供class作者以充分的实现弹性
protected并不比public更具封装性
23.宁以non-member,non-friedn替换member函数(可以增加封装性,包裹弹性和机能扩充性)
关于封装:如果某些东西被封装,它就不再可见,愈多东西被封装,愈少人可以看到它,而愈少人看到它,我们就有愈多的弹性去变化他,因为我们的改变仅仅直接影响看到改变的那些人事物。
推崇封装的原因:它使我们能够改变事物而只影响有限客户。
越多函数可以访问到的数据说明数据的封装性就越低。
24.若所有参数皆需类型转换,请为此采用non-member函数
例如
const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator(),lhs.denominator()* rhs.denominator());
}
Rational oneFourth(1,4);
Rational result;
result = oneFourth*2;
result = 2*oneFourth;
这样两个是都可以的,但是如果是成员函数那么就做不到这样。
25.考虑写出一个不抛出异常的swap函数(这个没怎么懂。。感觉不是很重要。。有知道的麻烦指教)
当std::swap对你的类型效率不高的时候你可以提供一个swap并且要确保这个swap不会抛出异常
(1)许多客户端错误可以因为导入新类型而获得预防(explicit的作用是防止隐式转换)
例如Date(int month,int day,int year);乍看正确,其实不然
解决方案是构造如下三类
struct Day
struct Month
struct Year
(2)预防客户错误的另一个方法是,限制类型内什么事可做,什么事不能做。
使自己的类型和内置类型基本一致
(3)关于tr1::shared_ptr指针
毫无疑问的是这个指针比原始指针大且慢,而且使用辅助动态内存,但是在许多应用中这些额外的执行成本并不显著,但是它"降低客户错误的成效"十分显著,所以遇到与内存有关的指针操作的时候大家可以考虑使用它。
19.设计class犹如设计type
20.宁以pass-by-reference-to-const替换pass-by-value(以传常引用调用替换传值调用)
关于pass-by-value的弊端:传值调用实际上函数参数是以实际实参的复件为初值,而调用端所获得的亦是函数返回值的一个复件,这些复件是由对象的copy构造函数产出,这可能使pass-by-value成为昂贵的(费时)的操作。
bool validateStudent(Student s);
bool validateStudent(const Student &s);
对于内置类型,STL的迭代器和函数对象而言其实pass-by-value的效率更高。
21.必须返回对象时别妄想返回reference
所谓reference只是名称,代表的是某个既有对象。
关于必须返回对象时的正确写法:
inline const Rational operator* (const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.n* rhs.n,lhs.d* rhs.d);
}
(1)绝不要返回pointer或reference指向一个local stack对象
(2)绝不要返回reference指向一个heap-allocated对象
(3)绝不要返回一个pointer或reference指向一个local static对象而有可能同时需要多个这样的对象。
22.将成员变量声明为private
好处:可以赋予客户访问数据的一致性,可细微划分访问控制,允诺约束条件获得保证,并提供class作者以充分的实现弹性
protected并不比public更具封装性
23.宁以non-member,non-friedn替换member函数(可以增加封装性,包裹弹性和机能扩充性)
关于封装:如果某些东西被封装,它就不再可见,愈多东西被封装,愈少人可以看到它,而愈少人看到它,我们就有愈多的弹性去变化他,因为我们的改变仅仅直接影响看到改变的那些人事物。
推崇封装的原因:它使我们能够改变事物而只影响有限客户。
越多函数可以访问到的数据说明数据的封装性就越低。
24.若所有参数皆需类型转换,请为此采用non-member函数
例如
const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator()*rhs.numerator(),lhs.denominator()* rhs.denominator());
}
Rational oneFourth(1,4);
Rational result;
result = oneFourth*2;
result = 2*oneFourth;
这样两个是都可以的,但是如果是成员函数那么就做不到这样。
25.考虑写出一个不抛出异常的swap函数(这个没怎么懂。。感觉不是很重要。。有知道的麻烦指教)
当std::swap对你的类型效率不高的时候你可以提供一个swap并且要确保这个swap不会抛出异常
相关文章推荐
- 【高质量代码】如何写出更高质量的C/C++代码(2):函数设计
- 如何写出高效C++(让自己习惯C++)
- C++在循环内和循环外定义变量的差异(如何写出高效的for循环)
- 如何写出高效C++(模板与泛型编程)
- 如何写出高效C++(继承与面向对象设计)
- 如何写出高效C++(资源管理)
- 如何写出高效C++(定制new和delete和杂项讨论)
- 如何理解c和c++的复杂类型声明
- C++设计的一个小缺陷——不必强制类普通成员函数在类体中声明
- [C++程序设计]如何编写高效的C++函数
- 如何设计高效合理的MySQL查询语句
- 如何理解c和c++的复杂类型声明
- 如何理解c和c++的复杂类型声明(转载)
- 转 如何理解c和c++ 的复杂类型声明
- 如何理解c和c++的复杂类型声明
- C/C++:如何理解复杂的声明
- C++ 之 高效使用STL(泛型算法设计原理解析)
- 如何理解c和c++的复杂类型声明
- 如何理解c和c++ 的复杂类型声明
- C/C++:如何理解复杂的声明