[英]How to overload ostream for a member struct of a templated class
我正在使用二叉樹在C ++中實現字典,我樹中的每個節點都有一個鍵( int
),item( string
)和左右子節點。
在此實現過程中,我重載了BinaryTree
類的ostream運算符以打印出樹的內容。
另外,我重載了ostream以使用Node
指針,然后打印出該節點的鍵和項 。
這很好。 然而,當我試圖使樹成為模板以使用任何類型的鍵或項重載時,這些操作符變得更加困難。
我將問題隔離開來使其更容易處理,另外,我嘗試過使用節點和節點指針來查看是否可以在沒有其他節點的情況下使用它。
這是我為測試問題所做的課程,這個類沒有模板化並且工作正常。
test.h
class myClass
{
public:
using Key = int;
myClass(Key);
friend std::ostream & operator<<(std::ostream &, const myClass &);
private:
struct Thing {
Key data;
Thing();
Thing(Key);
};
Thing* B;
Thing A;
void disp(std::ostream &) const;
friend std::ostream & operator<<(std::ostream &, myClass::Thing);
friend std::ostream & operator<<(std::ostream &, myClass::Thing *);
};
TEST.CPP
myClass::Thing::Thing(Key Num) { data = Num; }
myClass::myClass(Key Num)
{
A = Thing(Num); B = &A;
}
void myClass::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
std::ostream & operator<<(std::ostream & os, const myClass & c)
{
c.disp(os); return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing th)
{
os << th.data; return os;
}
std::ostream & operator<<(std::ostream & os, myClass::Thing *th)
{
os << th->data; return os;
}
有了這個類,我可以很容易地創建我的類和std::cout
的實例,它按預期提供輸出。 然后將此類轉換為模板:
template <class T> class myTemplate
{
public:
using Key = T;
myTemplate(Key);
template<class A>
friend std::ostream & operator<<(std::ostream &, const myTemplate<A> &);
private:
struct Thing;
Thing A;
Thing* B;
void disp(std::ostream &) const;
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing);
template <class A> friend std::ostream & operator<<(std::ostream &, typename myTemplate<A>::Thing *);
};
template <class T> struct myTemplate<T>::Thing
{
T data;
Thing() = default;
Thing(Key);
};
//Create new thing A with B a pointer to A
template <class T> myTemplate<T>::myTemplate(Key Num)
{
A = Thing(Num);
B = &A;
}
//Displays Node A & B
template <class T> void myTemplate<T>::disp(std::ostream & os) const
{
os << A << std::endl; os << B << std::endl;
}
template <class T> myTemplate<T>::Thing::Thing(Key Num)
{
data = Num;
}
//Overloading << will call disp function, in turn print A & B to stream
template<class T> std::ostream & operator<<(std::ostream & os, const myTemplate<T> & c)
{
c.disp(os); return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing th)
{
os << th.data; return os;
}
//Output a to stream
template <class A> std::ostream & operator<<(std::ostream & os, typename myTemplate<A>::Thing *th)
{
os << th->data; return os;
}
但是當我在main()
嘗試使用myTemplate
:
myTemplate Template(5);
cout << Template;
因為我收到錯誤,代碼將無法編譯:
Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'const myTemplate<std::string>::Thing' (or there is no acceptable conversion)
另外評論出這條線:
os << A << std::endl;
因此只有B
被輸出到流中,代碼將被編譯。 然而的數據B
不被輸出,只的存儲器地址B
。
我注意到在嘗試輸出B
時使用斷點代碼甚至不使用我定義的重載函數。 對於非模板化類,情況並非如此,因為我定義的重載用於A
和B
那么重載ostream運算符以適應struct成員的正確方法是什么?
為冗長的問題道歉,覺得我應該包括我自己決定的內容。
由於模板實現將在單個翻譯單元 (頭文件)本身中,因此通過撕開事物,您將不會獲得更多。 因此,將定義和非成員函數保留在類本身中,這將為您提供更清晰的代碼,並提高模板類的可讀性: 請參閱此
#include <iostream>
template <class T> class myTemplate
{
public:
using Key = T;
private:
struct Thing
{
T data;
Thing() = default;
Thing(Key Num) : data(Num) {}
};
Thing A;
Thing* B = nullptr;
public:
myTemplate(Key Num) : A(Thing(Num)), B(&A) {}
friend std::ostream & operator<<(std::ostream& out, const myTemplate &obj)
{
return out << obj.A << std::endl << obj.B << std::endl;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing thing)
{
return out << thing.data;
}
friend std::ostream & operator<<(std::ostream& out, typename myTemplate::Thing *thing)
{
return out << thing->data;
}
};
int main()
{
myTemplate<int> obj(10);
std::cout << obj;
return 0;
}
更新 :如果為結構Thing
提供兩個operator<<
重載的最終目的只是方便地調用myTemplate
類的operator<<
,那么你不需要它,而只是直接在operator<<
打印data
myTemplate
類。 這將再次減少相當數量的代碼( 如果是這種情況! )。
不過,現在您可以為myTemplate
類的非成員(朋友)函數(即operator<<
)提供myTemplate
,如下所示:
template <class T> class myTemplate; // forward declaration
template <class T> std::ostream& operator<<(std::ostream& out, const myTemplate<T> &obj);
template <class T> class myTemplate
{
private:
using Key = T;
private:
template <class Type = T> struct Thing
{
Type data;
Thing() = default;
Thing(const Key Num) : data(Num) {}
};
private:
Thing<> A;
Thing<> *B = nullptr;
public:
myTemplate(const Key Num) : A(Thing<>(Num)), B(&A) {}
friend std::ostream & operator<<<>(std::ostream& out, const myTemplate &obj);
};
template <class T> std::ostream & operator<<(std::ostream& out, const myTemplate<T> &obj)
{
return out << obj.A.data << std::endl << obj.B->data << std::endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.