EffectiveC++学习笔记-条款41|42

条款41 了解隐式接口和编译期多态
条款42 了解typename的双重含义

了解隐式接口和编译期多态

隐式接口是相对于函数签名所代码的显式接口而言的。当我们看到一个函数签名(即函数声明),比如说:
string getName(int StudentID);
我们就知道这个函数有一个整型的形参,返回值是string。

隐式接口

是由有效表达式组成的,考虑一个模板函数,像下面这样:

template <class T>
void TemplateFunction(T& w)
{
    if(w.size() > 10){…}
}

T可以是int,可以double,也可以是自定义的类型。光看这个函数声明,我们不能确定T具体是什么,但我们知道,要想通过编译,T必须要支持size()这个函数。也就是说,T中一定要有这样的函数接口声明。
ReturnValue size();
当然返回值ReturnValue不一定是int了,只要它能支持operator > (ReturnValue, 10)这样的运算即可。这种由表达式推判出来的函数接口,称之为隐式接口

简言之,显式接口由函数签名式构成,隐式接口由有效的表达式组成.

运行时多态和编译期多态

“运行时多态”它伴随着virtual关键字,本质是一个虚表和虚指针,在类对象构造时,将虚指针指向了特定的虚表,然后运行时就会根据虚表的内容进行函数调用。

那么“编译期多态”又是什么呢,从字面上来看,它发生在编译阶段,实际上就是template 这个T的替换,它可以被特化为int,或者double,或者用户自定义类型,这一切在编译期就可以决定下来T到底是什么,编译器会自动生成相应的代码(把T换成具体的类型),这就是编译期多态做的事情了,它的本质可以理解成自动生成特化类型版本,T可以被替换成不同的类型,比如同时存在int版本的swap与double版本的swap,形成函数重载。简言之,运行时多态是决定“哪一个virtual函数应该被绑定”,而编译期多态决定“哪一个重载函数应该被调用”。

了解typename的双重含义

正常的模板声明例如:

template<class T> class Widget;
template<typename T> class Widget;

这两种声明类型没有什么不同。

看一个代码:

template<typename C>
void print2nd(const C& container)
{
    if(container.size() >= 2)
    {
        typename C::const_iterator iter(container.begin());
    }
}

但是我们必须要告诉编译器C::const_iterator是一个类型,否则就无法识别到。这种就属于嵌套从属类型名称。
容器就是典型的嵌套从属类型:

using namespace std;

template< typename C >
void f(const C& con, typename C::iterator it){}

int main(int argc, char *argv[])
{
    vector<int> a;
    auto i = a.begin();
    f(a, i);

    cout <<"success";
    return 0;
}

万事总有例外,typename不可出现在base class list内的嵌套从属类型名称之前。也不可在member initialization list(成员初值列)中作为base class修饰符。例如:

//详细解释请查看书上P236
template
class Derived : public Base::Nested
{
public:
    explicit Derived(int x):
    Base::Nested(x)
    {
        typename Base::Nested temp;
    }
}

最后再看一个例子:

templateIterT>
void workWithIterator(IterT iter)
{
    //拷贝该迭代器中对象内容  
    typename std::iterator_traits::value_type temp(*iter);
}

假如IterT是vector::iterator则value_type即为int也就是 temp为int类型。

    typedef typename std::iterator_traits::value_type value_type;
    value_type temp(*iter);

这样就更容易看懂了。
详细的C++traits见后续内容!

总结重点

  • 请使用关键字typename来标识嵌套从属类型名称,但是不得在base class lists(基类列)或member initialization list(成员初值列)内以它作为base class修饰符。

你可能感兴趣的:(C++,编译期多态,运行时多态,模板,effective-c++)