如何写出高效C++(模板与泛型编程)
2016-08-08 17:14
274 查看
对Effective C++读了以后的总结(暑假没事干。。就是看书,从后往前的总结)
41。了解隐式接口和编译器多态
隐式接口:由一组有效表达式构成,表达式要求了相应的约束条件。
显式接口:则是在源代码中明确可见的指出接口的约束条件(比如函数参数的类型)。
所谓的编译期多态指的是:以不同的templete参数具现化function templates会导致调用不同的函数,这就是所谓的编译期多态。
classes接口是显式的,多态是通过virtual函数发生于运行期。
template接口是隐式的,多态是通过template具现化和函数重载解析发生于编译期。
42.了解typename的双重意义
首先了解什么是嵌套从属名称:
template<typename C>
void print2nd(const C& container)
{
if(container.size() >= 2)
{
C::const_iterator iter(container.begin());
.......
}
}
像iter这种依赖于template参数C的类型叫做从属名称,如果从属名称在class内呈嵌套状,那么我们称它为嵌套从属名称。
而int这样与C无关的就叫做非从属名称。
因为在知道C之前我们不知道C::const_iterator是不是一个类型,所以说这会导致这变成非有效类型,为了保证他时刻有效,我们需要在塔前main加一个typename,这是class做不到的
一般规则:任何时候你想在template中指涉一个嵌套从属类型名称,必须在紧邻他的前一个位置放上关键字typename。
但是,typename不能够出现在base class lists(基类列)或者member initialization list(成员初值列)内以它作为base class的修饰符。
43.学习处理模板化基类内的名称
可在derived class templates内通过"this->"指涉base class templates内的成员名称,或藉由一个明白写出的"base class 资格修饰符"完成。
例如
template <typename Company>
class LoggingMsgSender::public MsgSender<Company>
{
public:
...
void sendClearMsg(const MsgInfo& info)
{
this->sendClear(info);//假设sendClear被继承,所以成立,若去掉this,因为无法确切的知道他继承的MsgSender是一个什么样的函数,所以不到函数被具现化之前我们是不知道继承的类是什么样的,也就不知道是否有sendClear函数了
}
};
44.将与参数无关的代码抽离template
因为非类型模板参数而造成的代码膨胀往往可以消除,做法是以函数参数或class成员变量替换template参数。
原因:如果是非类型模板参数,比如int,那如果是非参数形式,对于不同的int就要生成不同的一份代码,但是其实这样的代码里面除了int值不同以外其他都相同,那么就造成了代码膨胀,而如果我们另外在类外面写一个带有参数的template函数那么所有的不同的int就只需要一份代码。
因为类型参数而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述的具现类型共享实现码。
如果你实现某些成员函数而他们操作强型指针(T*),你应该令他们调用另一个操作无类型(void*)指针的函数。
45.运用成员函数模板接受所有兼容类型
template <typename T>
class SmartPtr
{
public:
template<typename U>
SmartPtr(const SmartPtr<U>& other);
}
对任意类型T和任意类型U,可以根据SmartPtr<U>生成一个SmartPtr<T>,因为T有一个构造函数接受一个U参数,也就是根据U对象生成t,也就是泛化拷贝构造函数。
若是要加限制
template <typename T>
class SmartPtr
{
public:
template<typename U>
SmartPtr(const SmartPtr<U>& other):heldPtr(other.get()) {...}
T* get() const { return heldPtr; }
...
private:
T* heldPtr;
};
如果说你要完全掌控copy构造函数或者assignment操作,光是模板还不够,因为它并不会百分百生成相应,编译器还是会为你提供相应的函数,所以你需要自己再写一个复合你自己要求的copy函数和copy assignment操作符。
46.需要类型转换时请为模板定义非成员函数
template<typename T>
class Rational
{
public:
...
friend const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator()* rhs.numerator(),lhs.deo()*rhs.deo());
}
}
当我们编写一个class template,而她所提供之“与此template相关的”函数支持“所有参数之类型转换”时,请将那些函数定义为“class template 内部的friend函数”。
41。了解隐式接口和编译器多态
隐式接口:由一组有效表达式构成,表达式要求了相应的约束条件。
显式接口:则是在源代码中明确可见的指出接口的约束条件(比如函数参数的类型)。
所谓的编译期多态指的是:以不同的templete参数具现化function templates会导致调用不同的函数,这就是所谓的编译期多态。
classes接口是显式的,多态是通过virtual函数发生于运行期。
template接口是隐式的,多态是通过template具现化和函数重载解析发生于编译期。
42.了解typename的双重意义
首先了解什么是嵌套从属名称:
template<typename C>
void print2nd(const C& container)
{
if(container.size() >= 2)
{
C::const_iterator iter(container.begin());
.......
}
}
像iter这种依赖于template参数C的类型叫做从属名称,如果从属名称在class内呈嵌套状,那么我们称它为嵌套从属名称。
而int这样与C无关的就叫做非从属名称。
因为在知道C之前我们不知道C::const_iterator是不是一个类型,所以说这会导致这变成非有效类型,为了保证他时刻有效,我们需要在塔前main加一个typename,这是class做不到的
一般规则:任何时候你想在template中指涉一个嵌套从属类型名称,必须在紧邻他的前一个位置放上关键字typename。
但是,typename不能够出现在base class lists(基类列)或者member initialization list(成员初值列)内以它作为base class的修饰符。
43.学习处理模板化基类内的名称
可在derived class templates内通过"this->"指涉base class templates内的成员名称,或藉由一个明白写出的"base class 资格修饰符"完成。
例如
template <typename Company>
class LoggingMsgSender::public MsgSender<Company>
{
public:
...
void sendClearMsg(const MsgInfo& info)
{
this->sendClear(info);//假设sendClear被继承,所以成立,若去掉this,因为无法确切的知道他继承的MsgSender是一个什么样的函数,所以不到函数被具现化之前我们是不知道继承的类是什么样的,也就不知道是否有sendClear函数了
}
};
44.将与参数无关的代码抽离template
因为非类型模板参数而造成的代码膨胀往往可以消除,做法是以函数参数或class成员变量替换template参数。
原因:如果是非类型模板参数,比如int,那如果是非参数形式,对于不同的int就要生成不同的一份代码,但是其实这样的代码里面除了int值不同以外其他都相同,那么就造成了代码膨胀,而如果我们另外在类外面写一个带有参数的template函数那么所有的不同的int就只需要一份代码。
因为类型参数而造成的代码膨胀,往往可降低,做法是让带有完全相同二进制表述的具现类型共享实现码。
如果你实现某些成员函数而他们操作强型指针(T*),你应该令他们调用另一个操作无类型(void*)指针的函数。
45.运用成员函数模板接受所有兼容类型
template <typename T>
class SmartPtr
{
public:
template<typename U>
SmartPtr(const SmartPtr<U>& other);
}
对任意类型T和任意类型U,可以根据SmartPtr<U>生成一个SmartPtr<T>,因为T有一个构造函数接受一个U参数,也就是根据U对象生成t,也就是泛化拷贝构造函数。
若是要加限制
template <typename T>
class SmartPtr
{
public:
template<typename U>
SmartPtr(const SmartPtr<U>& other):heldPtr(other.get()) {...}
T* get() const { return heldPtr; }
...
private:
T* heldPtr;
};
如果说你要完全掌控copy构造函数或者assignment操作,光是模板还不够,因为它并不会百分百生成相应,编译器还是会为你提供相应的函数,所以你需要自己再写一个复合你自己要求的copy函数和copy assignment操作符。
46.需要类型转换时请为模板定义非成员函数
template<typename T>
class Rational
{
public:
...
friend const Rational operator*(const Rational& lhs,const Rational& rhs)
{
return Rational(lhs.numerator()* rhs.numerator(),lhs.deo()*rhs.deo());
}
}
当我们编写一个class template,而她所提供之“与此template相关的”函数支持“所有参数之类型转换”时,请将那些函数定义为“class template 内部的friend函数”。
相关文章推荐
- 如何写出高效C++(让自己习惯C++)
- 如何写出高效C++(设计与声明)
- C++在循环内和循环外定义变量的差异(如何写出高效的for循环)
- 如何写出高效C++(资源管理)
- 如何写出高效C++(定制new和delete和杂项讨论)
- 如何写出高效C++(继承与面向对象设计)
- 如何编写优质、高效、益于维护的C++代码
- C++模板编程:如何在编译器确定斐波那契数列?
- 如何写出高效的sql的一点想法及oracle常用hint用法
- 如何写出高效优美的C语言代码
- C++模板和泛型编程
- [SQL]如何写出高效的SQL
- 如何写出高效的Bug测试报告,给出9点建议
- [C++程序设计]如何编写高效的C++函数
- C++模板的缺点以及如何避免
- C++菜鸟学习笔记——模板与泛型编程
- 如何写出高效的sql的一点想法
- C++ 之 模板与泛型编程(二、模板实例化)
- 如何修改Carbide.C++ 1.2的模板文件格式
- 如何写出高效优美的C语言代码