多语言展示
当前在线:164今日阅读:55今日分享:34

c++ 类模板的使用

c++类模板与函数模板共同组成了c++的模板技术,因此了解模板的使用相当的重要。上一节介绍了函数模板,下面将详细介绍一下类模板的使用。
工具/原料

c++ 11以上

方法/步骤
1

1、举例子除了可以申明函数模板外,也还可以声明类模板。举个例子(实现一个堆栈):templateclass Stack {std::vector v;public:Stack();Stack(const Stack&); // T是同一类型的类模板才能拷贝Stack& operator=(const Stack&);void push(const T&);void pop();const T& top() const;bool empty() const;};templateStack::Stack(){}templateStack::Stack(const Stack& rhs) : v(rhs.v){}templateStack& Stack::operator=(const Stack& rhs){v = rhs.v;return *this;}templatevoid Stack::push(const T& x){v.emplace_back(x);}templatevoid Stack::pop(){assert(!v.empty());v.pop_back();}templateconst T& Stack::top() const{assert(!v.empty());return v.back();}templatebool Stack::empty() const{return v.empty();}

2

定义好类模板后,它的调用方法:int main(){using IntStack = Stack; // typedef Stack IntStackIntStack intStack; // Stack intStackintStack.push(42);std::cout << intStack.top(); // 42Stack stringStack;stringStack.push('hi');std::cout << stringStack.top(); // histringStack.pop();}

3

除了int类型外,模板实参可以是任何类型Stack doublePtrStack;Stack> intStackStack;

4

成员函数只有被调用到时才实例化如果类模板有static数据成员,每种实例化类型都会实例化static数据成员。static成员函数和数据成员只被同类型共享templateclass A {static std::size_t n;public:static std::size_t count();};templatestd::size_t A::n = 0;A a; // 实例化A::nA b, c, d; // 实例化A::n,bcd共享A::count()和A::nstd::size_t n = A::count(); // 实例化A::count()n = b.count(); // 使用A::count()n = A::count(); // 错误:必须指定模板参数,否则无法得知实例化版本

5

2、类模板的部分使用由于成员函数只有被调用到时才实例化,模板实参只要提供必要的操作,而非所有需要的操作。如Stack提供一个printOn对每个元素调用operator<<,即使没有对元素定义operator<<也能使用这个类。只有调用printOn时才会产生错误,因为这时不能对这些元素实例化operator<class Stack {...void printOn(std::ostream&) const;};template void Stack::printOn(std::ostream& os) const{for (const T& x : v) os << x << ' ';}Stack> s; // std::pair没有定义operator<

6

与其使用printOn函数打印元素,不如重载operator<<,然而通常operator<<会实现为非成员函数。下面在类内定义友元,它是一个普通函数templateclass Stack {...void printOn(std::ostream& os) const;friend std::ostream& operator<<(std::ostream& os, const Stack& stack) {stack.printOn(os);return os;}};

7

如果在类外定义友元,类模板参数不可见,事情会复杂很多有两个解决方案,一是隐式声明一个新的函数模板,并使用不同的模板参数templateclass Stack {…templatefriend std::ostream& operator<<(std::ostream&, const Stack&);};// 类外定义templatestd::ostream& operator<<(std::ostream& os, const Stack& stack){stack.printOn(os);return os;}

8

二是将友元前置声明为模板,而友元参数中包含类模板,这样就必须先前置声明类模板template // operator<<中参数中要求Stack模板可见class Stack;templatestd::ostream& operator<<(std::ostream&, const Stack&);// 随后就可以将其声明为友元templateclass Stack {…friend std::ostream& operator<< (std::ostream&, const Stack&);};// 类外定义templatestd::ostream& operator<<(std::ostream& os, const Stack& stack){stack.printOn(os);return os;}

9

同样,函数只有被调用到时才实例化,元素没有定义operator<<时也可以使用这个类,只有调用operator<<时才会出错Stack> s; // std::pair没有定义operator<