Exceptional C++学习笔记(2) 多态

来源:互联网 发布:mac下载器 编辑:程序博客网 时间:2024/05/17 04:12

第5条 泛型性的风味之一:基础

     1 C++模板提供了编译期多态的能力

       说到面向对象特性之一“多态”,通常指常规的多态,即通过虚函数实现的“动态多态”或者叫”运行期多态“,而该条款说的模板提供的“编译期间多态”,也可以叫“静态多态”。

       首先介绍下运行多态

        运行多态可以简单地概括为“一个接口,多种方法”,程序在运行时才决定调用的函数,它是面向对象编程领域的核心概念。C++多态性是通过虚函数来实现的,虚函数允许子类重新定义父类声明为virtual成员函数或析构函数(为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用。注: 构造函数不能是虚函数

 顺便说下成员函数的重载(overload)、覆盖(override)与隐藏(hidden)

重载

  1. 相同的范围(在同一个类中)
  2. 函数名字相同
  3. 参数不同
  4. virtual 关键字可有可无

覆盖(派生类函数覆盖基类函数)

  1. 不同的范围(分别位于派生类与基类)
  2. 函数名字相同
  3. 参数相同
  4. 基类函数必须有 virtual 关键字

 隐藏(派生类的函数屏蔽了与其同名的基类函数)

  1. 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无 virtual 关键字,基类的函数将被隐藏(注意别与重载混淆)
  2. 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有 virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)

     多态与非多态的实质区别就是函数地址是早绑定还是晚绑定。如果函数的调用,在编译器编译期间就可以确定函数的调用地址,并生产代码,是静态的,就是说地址是早绑定的。而如果函数调用的地址不能在编译器期间确定,需要在运行时才确定,这就属于晚绑定。

#include <iostream>using namespace std;class DemoOne{public:void f(bool someParm=true){ cout<<"DemoOne f functions\n";}void g(){ cout<<"DemoOne g functions\n";}// other functions...};class DemoTwo{public:void f(){ cout<<"DemoTwo f functions\n";}void g(double a=1.12,double b=1.123){ cout<<"DemoTwo g functions\n";}// other functions...};template<typename T>void h(T& t){t.f();t.g();}int main(){DemoOne one;DemoTwo two;h(one);h(two);system("pause");return 0;}

第7条 为什么不特例化函数模板

1 C++主要有哪两种形式的模板,他们分别如何进行特例化

  C++有类模板和函数模板之分。这两种模板的工作方式也不完全一样,最明显的区别就在于重载,普通的C++类是不能进行重载的,因此类模板也不能进行重载。另一方面,在同一作用域内,普通的C++函数如果名字相同,参数列表不同就会发生重载,因此函数模板也运行重载。

     首先说明下什么事特例化

一、函数模板特例化

当特例化一个函数模板时,必须为原模板中的每个模板参数都提供实参。使用关键字template后跟一个空尖括号<>,即template <>,以指出我们正在特例化一个模板。

template <typename T>  void fun(T a)  {      cout << "The main template fun(): " << a << endl;  }    template <>   // 对int型特例化  void fun(int a)  {      cout << "Specialized template for int type: " << a << endl;  }    int main()  {      fun<char>('a');      fun<int>(10);      fun<float>(9.15);      return 0;  }  
结果如下:
The main template fun(): a  Specialized template for int type: 10  The main template fun(): 9.15  

对于除int型外的其他数据类型,都会调用通用版本的函数模板fun(T a);对于int型,则会调用特例化版本的fun(int a)。注意,一个特例化版本的本质是一个实例,而非函数的重载。因此,特例化不影响函数匹配。

二、类模板特例化

除了特例化函数模板,我们还可以特例化类模板。下面是一个简单的例子:

template <typename T>  class Test{  public:      void print(){          cout << "General template object" << endl;      }  };    template<>   // 对int型特例化  class Test<int>{  public:      void print(){          cout << "Specialized template object" << endl;      }  };    int main()  {      Test<int> a;      Test<char> b;      Test<float> c;      a.print();      b.print();      c.print();      return 0;  }  
结果如下:

Specialized template object  General template object  General template object 
另外,与函数模板不同,类模板的特例化不必为所有模板参数提供实参。我们可以只指定一部分而非所有模板参数,这种叫做类模板的偏特化 或部分特例化(partial specialization)。例如,C++标准库中的类vector的定义:

template <typename T, typename Allocator>  class vector  {      /*......*/  };    // 部分特例化  template <typename Allocator>  class vector<bool, Allocator>  {      /*......*/  };  
在vector这个例子中,一个参数被绑定到bool类型,而另一个参数仍未绑定需要由用户指定。注意,一个类模板的部分特例化版本仍然是一个模板,因为使用它时用户还必须为那些在特例化版本中未指定的模板参数提供实参。

类模板可以被偏特例化或全特例化,函数模板则只能够被全特例化,不过函数模板可以被重载,所以我们可以通过重载也能达到类似偏特例化的效果



0 0
原创粉丝点击