當分離(友元函式 類模板)的宣告/定義時,會發生錯誤:
error LNK2001: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class Property<int> const &)" (??6@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AAV01@ABV?$Property@H@@@Z)
請注意,當使用沒有類模板的朋友函式時,反之亦然,一切正常,但是當將兩者一起使用時,會發生錯誤。
我試圖在 .cpp 檔案中實體化模板,但沒有成功。
另外,我在 .h 檔案的末尾包含了 .cpp 檔案,但它也不起作用。
類.h
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
friend std::ostream& operator<<(std::ostream& os, Property<PropertyType>& other);
};
類.cpp
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template <class PropertyType>
std::ostream& operator<<(std::ostream& os, Property<PropertyType>& other) {
os << other.m_property;
return os;
}
template Property<int>;
主檔案
int main() {
Property<int> num;
num = 100;
std::cout << num << "\n";
}
將宣告/定義分成兩個檔案并一起使用時,它們有什么問題?
uj5u.com熱心網友回復:
您的代碼片段有兩個問題。
第一個問題是您將實作放在源檔案而不是頭檔案中。所以要解決這個問題,只需將實作移動到頭檔案中。
第二個問題是,即使您將實作移到源檔案中,程式仍然無法運行(Demo)。這是因為您當前擁有的朋友宣告(對于多載opearator<<)是針對普通(非模板)函式的。也就是說,在您operator<<的類模板的原始代碼中,Property<>不是函式模板,而是在需要時用類模板實體化的“普通”函式。這就是我們所說的模板化物體。
但是您在源檔案(.cpp)中為多載的 operator<< 提供的定義是針對函式模板而不是針對普通函式的。因此,對于陳述句std::cout << num << "\n";,聯結器無法找到與operator<<您擁有朋友宣告的普通多載相對應的定義/實作。
有兩種方法可以解決這個問題:
方法一
在朋友宣告中添加一個單獨的引數子句。
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter cluase added here
//---------------------------------------------------vvvvv----------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};
template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
演示
方法二
在這里,我們提供多載的前向宣告operator<<。
//forward declaration for class template Property
template<typename T> class Property;
//forward declaration for overloaded operator<<
template<typename T> std::ostream& operator<<(std::ostream&,const Property<T>&);//note the const in the second parameter
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
//---------------------------------vvvvvvvvvvvvvv---------------------------------> angle brackets used here
friend std::ostream& operator<<<PropertyType>(std::ostream& os,const Property<PropertyType>& other);//also note the const in the second parameter
};
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
演示
方法三
如果你想在源檔案而不是頭檔案中提供實作,那么你應該添加
template std::ostream& operator<<(std::ostream& os, Property<int>& other);
除了為朋友宣告添加模板引數子句外,在源檔案中,如下所示:
類.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <iostream>
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter clause added
//---------------------------------------------------vvvvv--------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};
#endif
類.cpp
#include "class.h"
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template<typename PropertyType>
//----------------------------------------vvvvv------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
template class Property<int>;
template std::ostream& operator<<(std::ostream& os,const Property<int>& other);
主檔案
#include <iostream>
#include "class.h"
int main() {
Property<int> num;
num = 100;
std::cout << num << "\n";
}
演示
我所做的更改包括:
為朋友宣告添加了單獨的模板引數子句。這樣友元宣告是針對函式模板的。此外,我們指定了一個不同的型別引數,名為
T而不是PropertyType because otherwise the newPropertyTypewill shadow the outerPropertyType`。const在多載的第二個引數中添加了一個低級opeartor<<。在方法3中,在源檔案(class.cpp)中,添加了
template std::ostream& operator<<(std::ostream& os,const Property<int>& other);
對于多載的非成員函式operator<<。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/459544.html
