C++ 学习(2) ---- 基本语法介绍
C++ 基本语法(2)
C++基础语法 | 说明 |
---|---|
模板 | NA |
运算符重载 | NA |
强制类型转换 | static_cast,const_cast, reinterpret_cast,dynamic_cast |
const mutable关键字 | |
explicit 关键字 | |
inline 关键字 |
函数模板
C++ 中的模板分为函数模板和类模板两种
C++中,很多函数要求能够处理许多不同类型的数据,比如比较大小的函数,既要能够比较整数也要求能够比较字符串,这些算法处理的数据是不相同的,但是算法本身是相同的,这种情况下就可以使用函数模板来简化工作
示例代码:
template <typename T>
inline T const& Max(T const& a, T const& b) {
return a > b ? a : b;
}
T 表示一种抽象的数据类型,template <typename T> 也可以写成 template <class T>,译器会自动根据我们传入的标识符类型,来推导出相应的函数
调用形式:显示实例化或者隐式实例化(推导)
//test function teamplate
{
cout << "Max uint32_t ret = " << Max(10, 20) << endl;
//cout << "Max uint32_t ret = " << Max<uint32_t>(10, 20) << endl;
cout << "Max float ret = " << Max(1.0f, 2.1f) << endl;
//cout << "Max uint32_t ret = " << Max<float>(1.0f, 2.1f) << endl;
string s1 = "hello";
string s2 = "world";
//cout << "Max string ret = " << Max(s1, s2) << endl;
cout << "Max uint32_t ret = " << Max<string>(s1, s2) << endl;
}
模板类
下面的代码定义了一个stack 的模板类,类中使用vector 存储数据
template <typename T> //template <class T> is also ok
class Stack {
public:
Stack(uint32_t size);
void push(T const&);
T pop();
T top();
bool empty();
private:
vector<T> mvec;
};
template <typename T>
Stack<T>::Stack(uint32_t size) {
mvec.reserve(size);
}
template <typename T>
void Stack<T>::push(T const& a) {
mvec.push_back(a);
}
template <typename T>
T Stack<T>::pop() {
auto p = mvec.back();
mvec.pop_back();
return p;
}
template <typename T>
T Stack<T>::top() {
auto p = mvec.back();
return p;
}
template <typename T>
bool Stack<T>::empty() {
if (mvec.size() == 0) {
return true;
} else {
return false;
}
}
注意点:
- 定义模板类中的成员函数时,需要加上模板定义的开头 template <typename T>
- 模板类中的成员函数,用Stack<T>指定类名
隐式实例化的调用形式:
Stack<string> mystack(10);
mystack.push("pushA");
mystack.push("pushB");
mystack.push("pushC");
mystack.push("pushD");
string p = mystack.pop();
cout << "mysatck pop element: " << p << endl;
cout << "mysatck pop element: " << mystack.top() << endl;
cout << "mysatck empty: " << mystack.empty() << endl;
模板类的显式实例化
通常情况下,模板类的定义和实现是放在一起的,在.h和.cpp 文件中,当然也可以将它们像普通类一样分开放;
因为模板类、函数通常定义在头文件中,这些头文件会被很多cpp文件包含,在这些cpp文件中会多次使用这些模板;编译完后的可执行程序中会包含多份模板类的定义,然而实际上,整个程序中却只有一份模板类的定义,这个处理是在编译和链接过程中实现的,目前主流的实现模式有两种
-
Borland模式(先实例化模板类,再剔除)
Borland模式通过在编译器中加入与公共块等效的代码来解决模板实例化问题。在编译时,每个文件独立编译,遇到模板或者模板的实例化都不加选择地直接编译;在链接的时候将所有目标文件中的模板定义和实例化都收集起来,根据需要只保留一个;这种方法实现简单,但因为模板代码被重复编译,增加了编译时间,在这种模式下,我们编写代码应该尽量让模板的所有定义都放入头文件中,以确保模板能够被顺利地实例化,要支持此模式,编译器厂商必须更换支持此模式的链接器 -
Cfront模式(存储在模板存储库)
AT&T编译器支持此模式,每个文件编译时,如果遇到模板定义和实例化都不直接编译,而是将其存储在模板存储库中(template repository);模板存储库是一个自动维护的存储模板实例的地方,在链接时,链接器再根据实际需要编译出模板的实例化代码,这种方法效率高,但实现复杂。在这种模式下,我们应该尽量将非内联成员模板的定义分离到一个单独的文件中,进行单独编译。
g++实现的是Borland 模式,由于我们为每一份实例化生成代码,这样在大型程序中就有可能包含很多重复的实例化定义代码,虽然链接阶段,链接器会剔除这些重复的定义,但仍然会导致编译过程中的目标文件(或者共享库文件)过于庞大。这时候,我们就可以通过C++11的模板显式实例化的方法解决
下面定义Stack 模板类,实现是在 templateDemo.cpp 中
#include <stdint.h>
#include <iostream>
#include "vector"
#include "templateDemo.h"
template class Stack<uint32_t>; //显式实例化
template class Stack<string>; //显式实例化
/* template stack demo */
template <typename T>
Stack<T>::Stack(uint32_t size) {
mvec.reserve(size);
}
template <typename T>
void Stack<T>::push(T const& a) {
mvec.push_back(a);
}
template <typename T>
T Stack<T>::pop() {
auto p = mvec.back();
mvec.pop_back();
return p;
}
template <typename T>
T Stack<T>::top() {
auto p = mvec.back();
return p;
}
template <typename T>
bool Stack<T>::empty() {
if (mvec.size() == 0) {
return true;
}
else {
return false;
}
}
templateDemo.h 定义模版类Stack
#ifndef _TEMPLATEDEMO_
#define _TEMPLATEDEMO_
#include <string>
#include <vector>
using namespace std;
// template function Max
template <typename T>
inline T const& Max(T const& a, T const& b) {
return a > b ? a : b;
}
// template function templateprint
template <typename T>
void templateprint(T& a) {
cout << "demo print value: " << a << endl;
}
// templaye class Stack
template <typename T> //template <class T> is also ok
class Stack {
public:
Stack(uint32_t size);
void push(T const&);
T pop();
T top();
bool empty();
private:
vector<T> mvec;
};
#endif
在templateDemo.cpp 显式实例化 Stack 类模板,在其他文件中就可以很自由的include templateDemo.h;当然也可以将模板类Stack 定义实现放在一起,可以避免使用显示实例化;