您的位置:首页 > 编程语言 > C语言/C++

如何写出高效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函数”。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: