问题描述
如下面的这段代码所示,模板类里面有一个模板成员函数,其中有问题的地方我已经标注了,就是注释的那一行。请问为什么要用getValue()这个成员函数啊,如果没有main函数里面的语句,用x.value()是可以编译通过的,但是因为有了main()里面的语句,就必须要用个成员函数才行,这是为什么啊?
#include <iostream>template<typename T>class MyClass{private: T value;public: /*void assign(const MyClass<T>& x) {value = x.value; }*/ template <typename X> void assign(const MyClass<X>& x) {value = x.value; //这里有问题,要用getValue()才对。 } const T& getValue() const {return value; }};int main(){ MyClass<double> d; MyClass<int> i; d.assign(d); d.assign(i); return 0;}
问题解答
回答1:模板类在编译时会根据使用情况实例化成具体的类。
例如模板MyClass<T>在main中使用了不同的两个实例,则会实例化成MyClass<double>和MyClass<int>两个类,这两个类虽然是由同一个模板生成的,但他们是两个不同的类,没有友元关系,不能互相访问私有成员。
template<typename T>class MyClass{private: T value;public: /* ... */ template <typename X> void assign(const MyClass<X>& x) {value = x.value; // 1. 当类型 X 与 T 相同时,则为同一个类,可以访问自己的私有成员 // 当类型 X 与 T 不同时,则不是同一个类,不能访问对方的私有成员 } const T& getValue() const {return value; }};int main(){ MyClass<double> d; MyClass<int> i; d.assign(d); // 2. X 与 T 相同,正常编译运行 d.assign(i); // 3. X 与 T 不同,编译报错 return 0;}
与模板相关的错误通常很难在编译时查出,你可以把上述3的语句注释掉,就能正常编译运行了,但是如果想使3的语句能编译运行,就需要通过getValue成员来访问私有成员,使得T与X在实例化为不同类型时仍能运行。
另外,1处的语句使用了operator=进行赋值,则对MyClass<T>模板的类型T提出了一个潜在的要求,即类型T存在operator=参数可由类型X转化而得。
回答2:模板类是在编译时根据不同的特化生成不同的代码的。x.value使用了x的私有属性当然会报错,成员函数(setter和getter)提供接口不是很正常吗...如果没有main函数里的东西,编译器就不会生成MyClass<double>和MyClass<int>,只要模板类里没有语法错误就行。ps.我把value = x.value;改成value = x.vvvvvv;,clang和g++都编译通过了233