c++ 类模板的使用

2025-09-28 17:43:51

1、1、举例子

除了可以申明函数模板外,也还可以声明类模板。举个例子(实现一个堆栈):

template<typename T>

class Stack {

std::vector<T> v;

public:

Stack();

Stack(const Stack<T>&); // T是同一类型的类模板才能拷贝

Stack<T>& operator=(const Stack<T>&);

void push(const T&);

void pop();

const T& top() const;

bool empty() const;

};

template<typename T>

Stack<T>::Stack()

{}

template<typename T>

Stack<T>::Stack(const Stack<T>& rhs) : v(rhs.v)

{}

template<typename T>

Stack<T>& Stack<T>::operator=(const Stack<T>& rhs)

{

v = rhs.v;

return *this;

}

template<typename T>

void Stack<T>::push(const T& x)

{

v.emplace_back(x);

}

template<typename T>

void Stack<T>::pop()

{

assert(!v.empty());

v.pop_back();

}

template<typename T>

const T& Stack<T>::top() const

{

assert(!v.empty());

return v.back();

}

template<typename T>

bool Stack<T>::empty() const

{

return v.empty();

}

c++ 类模板的使用

c++ 类模板的使用

2、定义好类模板后,它的调用方法:

int main()

{

using IntStack = Stack<int>; // typedef Stack<int> IntStack

IntStack intStack; // Stack<int> intStack

intStack.push(42);

std::cout << intStack.top(); // 42

Stack<std::string> stringStack;

stringStack.push("hi");

std::cout << stringStack.top(); // hi

stringStack.pop();

}

c++ 类模板的使用

3、除了int类型外,模板实参可以是任何类型

Stack<double*> doublePtrStack;

Stack<Stack<int>> intStackStack;

c++ 类模板的使用

4、成员函数只有被调用到时才实例化

如果类模板有static数据成员,每种实例化类型都会实例化static数据成员。static成员函数和数据成员只被同类型共享

template<typename T>

class A {

static std::size_t n;

public:

static std::size_t count();

};

template<typename T>

std::size_t A<T>::n = 0;

A<std::string> a; // 实例化A<std::string>::n

A<int> b, c, d; // 实例化A<int>::n,bcd共享A<int>::count()和A<int>::n

std::size_t n = A<int>::count(); // 实例化A<int>::count()

n = b.count(); // 使用A<int>::count()

n = A::count(); // 错误:必须指定模板参数,否则无法得知实例化版本

c++ 类模板的使用

5、2、类模板的部分使用

由于成员函数只有被调用到时才实例化,模板实参只要提供必要的操作,而非所有需要的操作。如Stack提供一个printOn对每个元素调用operator<<,即使没有对元素定义operator<<也能使用这个类。只有调用printOn时才会产生错误,因为这时不能对这些元素实例化operator<<

template<typename T>

class Stack {

...

void printOn(std::ostream&) const;

};

template <typename T>

void Stack<T>::printOn(std::ostream& os) const

{

for (const T& x : v) os << x << ' ';

}

Stack<std::pair<int, int>> s; // std::pair没有定义operator<<

s.push({1, 2}); // OK

s.push({3, 4}); // OK

std::cout << s.top().first << s.top().second; // 34

s.printOn(std::cout); // 错误:元素类型不支持operator<<

c++ 类模板的使用

6、与其使用printOn函数打印元素,不如重载operator<<,然而通常operator<<会实现为非成员函数。下面在类内定义友元,它是一个普通函数

template<typename T>

class Stack {

...

void printOn(std::ostream& os) const;

friend std::ostream& operator<<(std::ostream& os, const Stack<T>& stack) {

stack.printOn(os);

return os;

}

};

c++ 类模板的使用

7、如果在类外定义友元,类模板参数不可见,事情会复杂很多

有两个解决方案,一是隐式声明一个新的函数模板,并使用不同的模板参数

template<typename T>

class Stack {

template<typename U>

friend std::ostream& operator<<(std::ostream&, const Stack<U>&);

};

// 类外定义template<typename U>

std::ostream& operator<<(std::ostream& os, const Stack<U>& stack)

{

stack.printOn(os);

return os;

}

c++ 类模板的使用

8、二是将友元前置声明为模板,而友元参数中包含类模板,这样就必须先前置声明类模板

template<typename T> // operator<<中参数中要求Stack模板可见class Stack;

template<typename T>

std::ostream& operator<<(std::ostream&, const Stack<T>&);

// 随后就可以将其声明为友元template<typename T>

class Stack {

friend std::ostream& operator<< <T> (std::ostream&, const Stack<T>&);

};

// 类外定义template<typename T>

std::ostream& operator<<(std::ostream& os, const Stack<T>& stack)

{

stack.printOn(os);

return os;

}

c++ 类模板的使用

9、同样,函数只有被调用到时才实例化,元素没有定义operator<<时也可以使用这个类,只有调用operator<<时才会出错

Stack<std::pair<int, int>> s; // std::pair没有定义operator<<

s.push({1, 2}); // OK

s.push({3, 4}); // OK

std::cout << s.top().first << s.top().second; // 34

std::cout << s << '\n'; // 错误:元素类型不支持operator<<

c++ 类模板的使用

声明:本网站引用、摘录或转载内容仅供网站访问者交流或参考,不代表本站立场,如存在版权或非法内容,请联系站长删除,联系邮箱:site.kefu@qq.com。
猜你喜欢