如下面的这段代码所示,模板类里面有一个模板成员函数,其中有问题的地方我已经标注了,就是注释的那一行。请问为什么要用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;
}
伊谢尔伦2017-04-17 13:28:52
模板類別在編譯時會根據使用情況實例化成具體的類別。
例如模板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
轉化而得。
迷茫2017-04-17 13:28:52
模板類別是在編譯時根據不同的特化產生不同的程式碼的。 x.value
使用了x的私有屬性當然會報錯,成員函數(setter
和getter
)提供介面不是很正常嗎...
如果沒有main
函數裡的東西,編譯器就不會產生MyClass<double>
和MyClass<int>
,只要模板類別裡沒有語法錯誤就行。
ps.我把value = x.value;
改成value = x.vvvvvv;
,clang和g++都編譯通過了233