一、typename与class的异同

1、啥时候既可以使用typename,又可以使用class?

当表示模板参数的时候,二者没有区别

2、啥时候只能使用typename,不能使用class?

当模板内部的成员表示一个类型时(标识嵌套从属类型名称),必须使用typename,而不能使用class,如果不使用typename编译器会把从属嵌套的类型视为一个成员变量,在遇到*时,会把*解析成乘法,而不是解引用符号

虽然书上是这样写的,但是实际并不使这样,在g++ 7.5.0测试发现,即使表示一个模板参数的类型成员(标识嵌套从属类型名称),typename和class也没有明显差异

示例1

template <class T>
class mytest
{class T::val_type func(const T &c);
};template <class T>
class T::val_type mytest<T>::func(const T &c)
{typename T::val_type *ptr;class T::val_type t;return typename T::val_type();
}

上述代码中的第10行必须加typename或者class关键字,否则,编译器会认为类型T中的static成员val_type与ptr相乘,而ptr没有定义,然而使用typename或者class都可以

但是,第11行只能用typename,不能用class,否则编译器报错

编译器提示,和class一起使用的表达式不正确,所以必须typename的原因是class后面的表达式不正确,而不是什么只能用typename不能用class

示例2

template <typename T>
void print(const T &con)
{class T::const_iterator pos;class T::const_iterator end(con.end());for (pos=con.begin();pos!=end;++pos){cout<<*pos<<endl;}
}

上述代码负责打印容器中的元素,第4,5行代码虽然都是表示T中的迭代器类型,但是使用class和typename都可以

所以,使用模板参数中的类型成员时,用class还是typename没有区别,只有class后的表达式不正确时,才必须使用typename

所以,既然能使用class的地方都能使用typename,但是有的地方还不能使用class,所以,在模板编程中,只使用typename表示类型就对了

3、例外

当嵌套从属的类出现在继承列表中时,此时不能使用typename表示类型

二、模板编程与继承

如果一个类模板被当做基类,如果子类不是模板类,那么派生列表要指定基类的模板实参,如果子类也是个类模板,那么,子类的派生列表可以使用自身的模板参数来指定基类的模板实参

示例

template <typename T>
class base
{
};template <typename T>
class derive:public base<T>
{
};class derive2:public base<int>
{
};

如果子类是个类模板,并且派生列表中的基类使用了子类的模板参数,那么在子类成员函数中调用基类成员函数时,要指定作用域

template <typename T>
class base
{
public:void functest(){cout<<__func__<<"in base"<<endl;}
};template <typename T>
class derive:public base<T>
{
public:void func(){functest();cout<<__func__<<"in derive"<<endl;}
};

上述代码无法编译通过

编译时,编译器提示functest是个依赖模板参数的函数,但是没有指明模板参数,所以编译器报错。所以解决办法有两个:

1、加上基类的作用域

emplate <typename T>
class derive:public base<T>
{
public:void func(){base<T>::functest();cout<<__func__<<"in derive"<<endl;}
};

2、在子类中重新定义一个functest

template <typename T>
class derive:public base<T>
{
public:void func(){functest();cout<<__func__<<"in derive"<<endl;}void functest(){cout<<__func__<<"in derive"<<endl;}
};

如果子类只是个普通类,但是要类模板做基类,那么必须将基类模板实例化

class derive2:public base<int>
{
public:void func(){functest();cout<<__func__<<"in derive"<<endl;}
};

此时编译器并不会报错,因为基类是个具体的类,创建该子类对象时,基类的this已经确定,可以找到基类的的functest

三、模板类和友元

如果一个类模板中包含一个友元,如果友元不是模板,那么,友元可以访问所有模板的实例,无须解释,和以前一样

如果友元是模板,那么友元模板的所有或者部分实例可以访问所有的类模板的实例

示例

template <typename T>
class friend1
{};template <typename T>
class friend2
{};template <typename T1>
class test2
{template <typename T2>friend class friend1;//类模板friend1的所有实例都是test2实例的友元friend class friend2<T1>;//只有用T1实例化的类才是test2的友元
};

四、类模板与static成员

类模板的每个实例类都各自拥有类模板中的static成员

示例

template <typename T>
class statictest
{static void func() {}static int si;
};template <typename T>
int statictest<T>::si=0;int main(int argc, char const *argv[])
{statictest<int> t;int i=t.si;//int i2=statictest::si;
}

因为static成员是各个实例化的模板类各自所有,而上述代码中的第15行没有指定模板参数,需要注释掉

static成员函数和其他类模板的成员函数一样,只有在被调用时才会被实例化产生代码

参考

《C++ Template》

《C++ Primer》

《Effective C++》

欢迎大家评论交流,作者水平有限,如有错误,欢迎指出

C++知识点61——typename与class、模板编程与继承、模板类和友元、类模板与static成员相关推荐

  1. C++快速讲解(九):I/O操作、模板编程、容器、函数对象

    C++快速讲解(九):I/O操作.模板编程.容器.函数对象 1.I/O操作 1.1 基本输入输出 1.2 string 流 1.3 读取文件 1.4 写入文件 2.模板编程 2.1函数模板 2.1.1 ...

  2. C++ - 模板函数须要类型转换时使用友元(friend)模板函数

    模板函数须要类型转换时使用友元(friend)模板函数 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24357301 非模板函数 ...

  3. C++友元函数、友元类与类模板

    文章目录 一.普通函数声明为友元涵数 二.声明类的成员函数为其他类的友元函数 三.类模板的使用 一.普通函数声明为友元涵数 #include <iostream> using namesp ...

  4. 友元函数,友元类,类模板

    C++提供友元机制,允许外部类和函数访问类的私有成员和保护成员的辅助方法,即将它们声明为一个给定类的友元类(或友元函数),使其具有类成员函数的访问权限.但友元本身不是类的成员,它不属于任何类. 优点: ...

  5. 模板编程中typename用法

    模板编程中typename用法 文章目录 模板编程中typename用法 typename的常规用法 typename的第二个用法:修饰类型 typename使用规则 typename的常规用法 ty ...

  6. 【C++模板编程入门】模板介绍、模板定义、函数模板、类模板、模板的继承

    1.模块的引入 1.1.示例代码 #include <iostream> #include <string>using namespace std;//用template声明T ...

  7. 【C++ 语言】面向对象 ( 模板编程 | 函数模板 | 类模板 )

    文章目录 函数模板 类模板 代码示例 函数模板 1. 模板编程 : 类似于 Java 中的泛型编程 ; ① 函数模板 : 对应着 Java 中的泛型方法 ; ② 类模板 : 对应 Java 中的泛型类 ...

  8. C++模板编程之类型萃取 惊鸿一瞥

    一.从模板函数std::distance(计算迭代器的距离)开始 #include <iostream> #include <vector> #include <list ...

  9. C++模板编程Demo

    PS:今天在网上看到一篇讲C++模板编程的博客,还算是比较的通俗易懂,在这里留一份,没事看看...... 当我们越来越多的使用C++的特性, 将越来越多的问题和事物抽象成对象时, 我们不难发现:很多对 ...

最新文章

  1. JavaScript 数据类型转换
  2. 面试必备:6个你必须熟练掌握的机器学习算法
  3. jaxp的Sax解析
  4. 全血微量元素团标今起实施 李喜贵:两项标准填补国内外空白
  5. MongoDB 语法和mysql语法对比学习
  6. JavaWeb之国际化
  7. Texture Inspection 纹理检验halcon算子,持续更新
  8. Python 元组(Tuple)操作详解
  9. 编译原理 计算机科学丛书_计算机科学导论(二)
  10. 管理系统中的计算机应用数据库系统,自考管理系统中的计算机应用重点: 数据库系统(1)...
  11. yii2环境搭建(ubuntu下nginx+php+mysql+yii2)
  12. python操作linux命令行_python调用调用Linux命令
  13. [转]五个值得关注的图形数据库
  14. 网站搭建 (第03天) 分页功能
  15. OJDBC版本之间的区别
  16. Pycharm CPU占用100%
  17. 数据分析入门-第四天
  18. JS中attr和prop区别
  19. python刷题:哥德巴赫猜想
  20. 《满族姓氏寻根大全·满族老姓全录》

热门文章

  1. Postgresql在Windows下的解压安装
  2. 6.Java集成开发环境
  3. 修改PHP上传文件大小限制的方法
  4. [译] PHP7 数组:HashTable
  5. NodeJS API Process全局对象
  6. Liunx 查看硬件信息
  7. 20个非常有用的Java程序片段
  8. 请给出一个算法,使之对于给定的介于0到k之间的n个整数进行预处理,并能在O(1)时间内,回答出输入的整数中有多少个落在区间[a..b]内,你给出的算法上预处理时间应是O(n+k)。...
  9. 网络巨头秘修域名重大疏漏 互联网免遭黑客控制
  10. Jsp实现在线影院售票系统