2015-10-18 40 views
0

在之前的項目中,我遇到過類似的錯誤,所以我決定從新方法開始,並且仍然遇到同樣的問題。我有一個鍵值對模板類,除了流操作符之外,一切都正常。我有<<接受kvp_node<key, elem> &kvpkvp_node<key, elem> *kvp的模板。我能夠創建kvp_node對象並使用它們的成員函數,而不存在任何問題。但是,如果我嘗試做一些事情,如:模板化的流操作員,未解決的外部問題

kvp_node<char, int> test('A', 10); 
std::cout << test; 

它給我的無法解析的外部操作錯誤。 我覺得我已經正確定義了我的流操作符。如果我嘗試只是做:

kvp_node<char, int> name('J', 12); 
std::cout << name.elm_(); 

它的工作原理沒有錯誤,這就是爲什麼這是混亂的,因爲所有的ostream操作確實是

os << (kvp_node<key, elem> test(key, elem)).elm_()

這是我的頭文件:

#ifndef DICT_H_ 
#define DICT_H_ 
#include<iostream> 
#include<fstream> 


//Stores Key Value pairs in a linked node can be used 
//to implement various KV based ADTs 
//kvp_nodes can be compared using normal comparator 
//operations. These operations will use the comparators 
//for the key class type, so if the key class is a user 
//defined type, they must define the comparators for the 
//class 
template<typename key, typename elem> 
class kvp_node { 
    bool setinel; 
    key k_val; 
    elem e_val; 
    kvp_node<key, elem> *next; 
    kvp_node<key, elem> *prev; 
public: 
    //default constructor 
    kvp_node(); 
    //use this constructor 
    kvp_node(key k, elem e, bool set = false); 
    //destructor 
    ~kvp_node(); 
    //copy constructor 
    kvp_node(const kvp_node<key, elem> &kvp); 
    //assignment constructor 
    void operator=(const kvp_node<key, elem> &kvp_); 

    //returns keyvalue 
    key key_(); 
    //returns element 
    elem elm_(); 

    //sets key value 
    void set_key(key k); 
    //sets element value 
    void set_elm(elem e); 

    //comparators, all will use the default comparators for the key type 
    bool operator==(kvp_node<key, elem> &kvp); 
    bool operator>=(kvp_node<key, elem> &kvp); 
    bool operator<=(kvp_node<key, elem> &kvp); 
    bool operator>(kvp_node<key, elem> &kvp); 
    bool operator<(kvp_node<key, elem> &kvp); 

    //returns next node 
    kvp_node<key, elem> *gnext(); 
    //returns previous node 
    kvp_node<key, elem> *gprev(); 

    //node linking functions 
    //sets the next node 
    void set_next(kvp_node<key, elem> *kvp); 
    //sets the previous node 
    void set_prev(kvp_node<key, elem> *kvp); 
    //links node a forward to b and b backward to a 
    void link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B); 

    //setinel functions 
    //makes setinel 
    void set_set(); 
    //returns setinel value 
    bool set(); 

    //standard io stream operators 
    //ostream << 
    friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> &kvp); 
    friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> *kvp); 
    //istream 
    //add later 

    //standard file stream operators 
    //ofstream << 
    friend std::ofstream& operator<<(std::ofstream &fo, kvp_node<key, elem> &kvp); 
    friend std::ofstream& operator<<(std::ofstream &fo, kvp_node<key, elem> *kvp); 
    //ifstream 
    //add later 
}; 


//constructors, destructors, assignment 
template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node() { 
} 

template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node(key k, elem e, bool set) { 
    k_val = k; 
    e_val = e; 
    setinel = set; 
} 

template<typename key, typename elem> 
kvp_node<key, elem>::~kvp_node(){ 

} 

template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node(const kvp_node<key, elem> &kvp) { 
    k_val = kvp.key_(); 
    e_val = kvp.elm_(); 
    setinel = kvp.set(); 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::operator=(const kvp_node<key, elem> &kvp) { 
    k_val = kvp.key_(); 
    e_val = kvp.elm_(); 
    setinel = kvp.set(); 
} 
// ================================== 
//get object values 
template<typename key, typename elem> 
key kvp_node<key, elem>::key_() { 
    return k_val; 
} 

template<typename key, typename elem> 
elem kvp_node<key, elem>::elm_() { 
    return e_val; 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::set() { 
    return setinel; 
} 
// ================================== 
//set object values 
template<typename key, typename elem> 
void kvp_node<key, elem>::set_key(key k) { 
    k_val = k; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_elm(elem e) { 
    e_val = e; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_set() { 
    setinel = true; 
} 
// ================================= 
//get neighbor kv pair nodes 
template<typename key, typename elem> 
kvp_node<key, elem> *kvp_node<key, elem>::gnext() { 
    return next; 
} 

template<typename key, typename elem> 
kvp_node<key, elem> *kvp_node<key, elem>::gprev() { 
    return prev; 
} 
// ================================= 
//set neighbor kv pair nodes 
template<typename key, typename elem> 
void kvp_node<key, elem>::set_next(kvp_node<key, elem> *kvp) { 
    next = kvp; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_prev(kvp_node<key, elem> *kvp) { 
    prev = kvp; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B) { 
    A->set_next(B); 
    B->set_prev(A); 
} 
// ================================== 
//comparison operators 
template<typename key, typename elem> 
bool kvp_node<key, elem>::operator<(kvp_node<key, elem> &kvp) { 
    return (k_val < kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator>(kvp_node<key, elem> &kvp) { 
    return (k_val > kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator<=(kvp_node<key, elem> &kvp) { 
    return (k_val <= kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator>=(kvp_node<key, elem> &kvp) { 
    return (k_val >= kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator==(kvp_node<key, elem> &kvp) { 
    return (k_val == kvp.key_()) ? (true) : (false); 
} 
// ================================== 
//stream operators 

template<typename key, typename elem> 
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem> &kvp) { 
    os << kvp.elm_(); 
    return os; 
} 

template<typename key,typename elem> 
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem> *kvp) { 
    os << kvp->elm_(); 
    return os; 
} 

#endif 

它是如何使用所有其他類成員,但流操作符不工作?

回答

1

我得到它的工作。這是我的改變。 (我抨擊提交,所以原諒我,而我修正格式)。

  • 刪除了不同操作員的好友功能。既然你有獲得者,那麼這些就足夠了。
  • 使所有getter爲const。如果您嘗試在STL容器中使用此內容,則會丟棄限定符的錯誤。
  • 使所有流操作符都接受一個類的const實例。

代碼

#include<iostream> 
    #include<fstream> 


//Stores Key Value pairs in a linked node can be used 
//to implement various KV based ADTs 
//kvp_nodes can be compared using normal comparator 
//operations. These operations will use the comparators 
//for the key class type, so if the key class is a user 
//defined type, they must define the comparators for the 
//class 
template<typename key, typename elem> 
class kvp_node { 
    bool setinel; 
    key k_val; 
    elem e_val; 
    kvp_node<key, elem> *next; 
    kvp_node<key, elem> *prev; 
public: 
    //default constructor 
    kvp_node(); 
    //use this constructor 
    kvp_node(key k, elem e, bool set = false); 
    //destructor 
    ~kvp_node(); 
    //copy constructor 
    kvp_node(const kvp_node<key, elem> &kvp); 
    //assignment constructor 
    void operator=(const kvp_node<key, elem> &kvp_); 

    //returns keyvalue 
    key key_()const; 
    //returns element 
    elem elm_()const; 

    //sets key value 
    void set_key(key k); 
    //sets element value 
    void set_elm(elem e); 

    //comparators, all will use the default comparators for the key type 
    bool operator==(kvp_node<key, elem> &kvp)const; 
    bool operator>=(kvp_node<key, elem> &kvp)const; 
    bool operator<=(kvp_node<key, elem> &kvp)const; 
    bool operator>(kvp_node<key, elem> &kvp)const; 
    bool operator<(kvp_node<key, elem> &kvp)const; 

    //returns next node 
    kvp_node<key, elem> *gnext(); 
    //returns previous node 
    kvp_node<key, elem> *gprev(); 

    //node linking functions 
    //sets the next node 
    void set_next(kvp_node<key, elem> *kvp); 
    //sets the previous node 
    void set_prev(kvp_node<key, elem> *kvp); 
    //links node a forward to b and b backward to a 
    void link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B); 

    //setinel functions 
    //makes setinel 
    void set_set(); 
    //returns setinel value 
    bool set()const; 

}; 


//constructors, destructors, assignment 
template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node() { 
} 

template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node(key k, elem e, bool set) { 
    k_val = k; 
    e_val = e; 
    setinel = set; 
} 

template<typename key, typename elem> 
kvp_node<key, elem>::~kvp_node(){ 

} 

template<typename key, typename elem> 
kvp_node<key, elem>::kvp_node(const kvp_node<key, elem> &kvp) { 
    k_val = kvp.key_(); 
    e_val = kvp.elm_(); 
    setinel = kvp.set(); 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::operator=(const kvp_node<key, elem> &kvp) { 
    k_val = kvp.key_(); 
    e_val = kvp.elm_(); 
    setinel = kvp.set(); 
} 
// ================================== 
//get object values 
template<typename key, typename elem> 
key kvp_node<key, elem>::key_()const{ 
    return k_val; 
} 

template<typename key, typename elem> 
elem kvp_node<key, elem>::elm_()const{ 
    return e_val; 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::set()const{ 
    return setinel; 
} 
// ================================== 
//set object values 
template<typename key, typename elem> 
void kvp_node<key, elem>::set_key(key k) { 
    k_val = k; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_elm(elem e) { 
    e_val = e; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_set() { 
    setinel = true; 
} 
// ================================= 
//get neighbor kv pair nodes 
template<typename key, typename elem> 
kvp_node<key, elem> *kvp_node<key, elem>::gnext() { 
    return next; 
} 

template<typename key, typename elem> 
kvp_node<key, elem> *kvp_node<key, elem>::gprev() { 
    return prev; 
} 
// ================================= 
//set neighbor kv pair nodes 
template<typename key, typename elem> 
void kvp_node<key, elem>::set_next(kvp_node<key, elem> *kvp) { 
    next = kvp; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::set_prev(kvp_node<key, elem> *kvp) { 
    prev = kvp; 
} 

template<typename key, typename elem> 
void kvp_node<key, elem>::link_nodes(kvp_node<key, elem> *A, kvp_node<key, elem> *B) { 
    A->set_next(B); 
    B->set_prev(A); 
} 
// ================================== 
//comparison operators 
template<typename key, typename elem> 
bool kvp_node<key, elem>::operator<(kvp_node<key, elem> &kvp)const{ 
    return (k_val < kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator>(kvp_node<key, elem> &kvp)const{ 
    return (k_val > kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator<=(kvp_node<key, elem> &kvp)const{ 
    return (k_val <= kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator>=(kvp_node<key, elem> &kvp)const{ 
    return (k_val >= kvp.key_()) ? (true) : (false); 
} 

template<typename key, typename elem> 
bool kvp_node<key, elem>::operator==(kvp_node<key, elem> &kvp)const{ 
    return (k_val == kvp.key_()) ? (true) : (false); 
} 
// ================================== 
//stream operators 

template<typename key, typename elem> 
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem>const& kvp) { 
    os << kvp.key_() << ", " << kvp.elm_(); 
    return os; 
} 

template<typename key,typename elem> 
std::ostream &operator<<(std::ostream &os, kvp_node<key, elem>const* kvp) { 
    os << kvp->elm_(); 
    return os; 
} 

int main(int argc, char* argv[]) 
{ 

    kvp_node<int,double> foo01(1, 2); 

    std::cout << foo01 << std::endl; 

    return 0; 
} 
+0

非常好,爲什麼從類中刪除流運算符聲明修復了這個問題? 'const const kvp_node &kvp'和'kvp_node const&kvp' – Anandamide

+0

之間的區別是什麼?從類中刪除好友功能不能解決問題。我只是刪除他們,因爲他們沒有必要,因爲你有所有私人成員的獲得者。修正它在'operator <<'定義中使用const kvp_node實例的東西。 – msmith81886

+0

啊有道理。我可以繼續我的項目感謝你:) – Anandamide

1

朋友模板一般很難正確地實現。一般來說,最好的方法是將它們內聯聲明。這樣一來,你就可以訪問私有成員:

template<typename key, typename elem> 
class kvp_node { 
    ... 
    friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> &kvp) { 
     os << kvp.e_val; 
     return os; 
    } 
    friend std::ostream& operator<<(std::ostream &os, kvp_node<key, elem> *kvp) { 
     os << kvp->e_val; 
     return os; 
    } 

    ... 
} 

但是除了那幾件我永遠不會宣佈運營商std::ofstream,因爲std::ofstream一個std::ostream,所以第二個定義是無用的。

而我不會有operator <<將指針看作是參考。 cout已經知道如何顯示指向任何指針,並且不顯示指向的值。在API中顯示指向的值會混淆未來的用戶。