-
类模板和函数模板一样,使用关键字
template
引入一个类模板。类模板是创建类的模式,通过提供模板参数来实现,例如Point<int>
。 -
类模板的成员函数本身就是函数模板,使用相同的模板参数,只是将模板参数提供给类,而不是函数,就像在下面示例中函数
Point<T>::moveTo
实现的那样。 -
每当使用不同的模板参数时,编译器就会生成一个新的类实例,具有新的成员函数。
也就是说,Point<int>::moveTo
是一个函数,Point<double>::moveTo
是另一个函数,这正是手动编写这些函数会发生的情况。如果两个不同的源文件都使用Point<int>
,编译器和链接器会确保它们共享同一个模板实例。 -
也正因为如此不能把一个
Point<int>
对象赋给一个Point<float>
对象,详见下面代码中注释掉的pt3 = pt2
后面的报错信息。 -
下面代码也给出了类内又有模板的实现方式。
#include <iostream>
#include <vector>
template<class T>
class Point{
public:
Point(T x, T y):x_(x), y_(y){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point(const Point& pt): x_(pt.x_), y_(pt.y_){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(const Point& pt)& {
Point(pt.x_, pt.y_).swap(static_cast<Point&>(*this));
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
Point(Point&& pt) noexcept: x_(pt.x_), y_(pt.y_) {
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
Point& operator=(Point&& pt)& noexcept{
x_ = pt.x_;
y_ = pt.y_;
std::cout << __PRETTY_FUNCTION__ << std::endl;
return *this;
}
void swap(Point& pt) noexcept{
std::swap(x_, pt.x_);
std::swap(y_, pt.y_);
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
virtual ~Point(){
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
T getX()const{
return x_;
}
T getY()const{
return y_;
}
void moveTo(T x, T y);
/*【类内又有模板】方式一,在类内声明,在类外定义,类外定义时需要注意模板头template header的堆叠方式,上面是类模板头、下面是函数模板头 */
template<class U>
U ratio() ;
/*【类内又有模板】方式二,在类内定义 */
template<class V>
V multiply() {
return static_cast<V>(x_) * static_cast<V>(y_);
}
private:
T x_;
T y_;
};
template<class T>
void Point<T>::moveTo(T x, T y){
x_ = x;
y_ = y;
}
template<class T>
template<class U>
U Point<T>::ratio() {
return static_cast<U>(x_) / static_cast<U>(y_); // omit devided by zero.
}
int main() {
Point<int> pt1(1, 2);
Point<float> pt2(3.4, 5.6);
Point<int> pt3(pt1);
pt3 = pt1;
//pt3 = pt2; // error: no match for 'operator=' (operand types are 'Point<int>' and 'Point<float>')
std::cout << "x = "<< pt3.getX() << ", y = " << pt3.getY() << std::endl; // x = 1, y = 2】
pt3.moveTo(5, 6);
std::cout << "x = "<< pt3.getX() << ", y = " << pt3.getY() << std::endl; // x = 5, y = 6
std::cout << pt3.ratio<float>() << std::endl; // 0.833333
std::cout << pt3.multiply<float>() << std::endl; // 30
}