2012-03-23 70 views
2

我在指針上調用operator<<時遇到問題。我已經通過搜索並在Google上提出了我的問題,但所有提出的解決方案都無法解決我的問題。爲了說明我的問題,請參見簡化一塊我的代碼:已重載的std :: ostream運算符<<未調用,流獲取變量地址而不是對象

Marker.h

class Marker { 
    ... 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
     out << "Marker " << marker._name << " of type " << marker._type << " at position " << marker._position; 
     return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
     out << *marker; 
     return out; 
} 

Landmark.h

class Landmark { 
     ... 
     Marker* m_marker; 
     ... 
}; 

Landmark.cpp

void Landmark::print(std::ostream& out) 
{ 
    out << "Marker GENERIC: " << m_marker << std::endl; 
    //out << "Marker GENERIC: " << *m_marker << std::endl; 
} 

這不會在Visual Studio 2008下鏈接。我得到一個unresolved external symbol錯誤的負載。如果我刪除friend std::ostream& operator<<(std::ostream& out, Marker* marker);,代碼編譯,但不是預期的格式化輸出,我只獲得指向標記Marker* Landmark::m_marker的指針的內存地址。取消註釋第二行將我的代碼變成無法解讀的代碼。

我應該如何重載operator<<以便我得到正確的輸出?

我將不勝感激任何幫助!

+0

注:爲指針過載,兩件事情失蹤。它應該讀取'Marker const * marker',因爲'Marker'實例沒有任何突變;它應該測試無效,以防萬一,在這種情況下可能輸出''。 – 2012-03-23 15:29:16

+0

如果您嘗試在其自己的編譯單元(即在.cpp文件中)中定義'std :: ostream&operator <<(std :: ostream&out,Marker * marker)'作爲(非內聯)函數,這使鏈接器開心? – 2012-03-23 14:34:18

+0

然後編譯器並不爭論,但包含此DLL的項目無法編譯:函數std :: ostream&operator <<(std :: ostream&out,Marker * marker)上的'unresolved external symbol''。這個函數是否應該在全局命名空間中定義?就我而言,我所有的類和重載的運算符函數都位於我的名字空間內。 – 2012-03-23 14:45:29

回答

2

下面是一個簡單的例子:

#include <iostream> 

namespace mine { 
class Marker { 
public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
}; 

inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
} 

inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
} 
} // namespace mine 

int main() { 
    mine::Marker marker; 
    mine::Marker* m = &marker; 

    std::cout << m << "\n"; 
} 

和它的作品as expected

您指向的錯誤是鏈接器錯誤,它告訴您編譯器向未發出函數的方法發出調用。

我會假設你對我們說謊或者Visual Studio再次出錯。

  • 如果你騙(即不復制確切的代碼):注意definining的inline方法時,整個身體的方法應包括使用前,因此Landmark.cpp應包括方法的定義。
  • 或者,可能需要通過在加入VS之前預先聲明函數來幫助VS,以便VS知道它們確實存在於mine命名空間中,而不是位於全局命名空間中。

喜歡的東西:

namespace mine { 
    class Marker; 

    std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    std::ostream& operator<<(std::ostream& out, Marker* marker); 

    class Marker { 
    public: 
    friend std::ostream& operator<<(std::ostream& out, const Marker& marker); 
    friend std::ostream& operator<<(std::ostream& out, Marker* marker); 
    }; 

    inline std::ostream& operator<<(std::ostream& out, const Marker& marker) { 
    out << "Marker"; 
    return out; 
    } 

    inline std::ostream& operator<<(std::ostream& out, Marker* marker) { 
    out << *marker; 
    return out; 
    } 
} // namespace mine 
+0

感謝您的廣泛答覆!向編譯器解釋函數在本地名稱空間中的第二個技巧已經奏效。問題可能在於我稱operator <<關於operator <<內的另一個對象,並且同樣的錯誤發生了兩次,所以很難追蹤它。 – 2012-03-26 06:38:25

+0

@PavloDyban:我有VS2003的這個bug(如果內存服務正確),它與「遞歸」無關。通常'friend'聲明應該引入在類的名字空間中聲明的函數,但似乎如果沒有先前的聲明存在,VS會絆倒它。我不確定這是不是標準指定的(我希望它是一個錯誤)。 – 2012-03-26 07:16:11

0

更改此

friend std::ostream& operator<<(std::ostream& out, Marker* marker); 

對此

friend std::ostream& operator<<(std::ostream& out, Marker marker); 

然後用這個

out << "Marker GENERIC: " << *m_marker << std::endl; 

你的輸出操作期待一個指針,而你正在通過實際的對象。

+1

根據Marker的實現方式,按值傳遞它可能不是一個好主意 - 可能更好地將第二個參數設置爲流操作符const marker&marker而不是「Marker marker」。 – 2012-03-23 14:32:20

+0

謝謝您的評論!我用指針隱藏了重載作爲參數,而是使用了引用指針。這與您通過按值傳遞標記所提出的幾乎相同。但是,我希望我在'out <<「標記GENERIC:」<< * m_marker << std :: endl;''一行中沒有星號。我應該如何重載我的操作符來獲取指向'Marker'的指針並輸出對象的內容? – 2012-03-23 14:51:38

1

現在,你有重載採取指針和對象的引用。你傳遞一個指針,所以引用的重載將不會被使用。

你想反過來:擺脫需要一個指針的重載,並使用需要引用的重載。通過取消引用指針使用它:out << *m_marker;

+0

謝謝!你給了我一個正確的建議!現在,如果我仍然想離開'out <<「標記GENERIC:」<< m_marker << std :: endl;',即通過傳遞標記對象的地址,我應該如何重載'operator <<' ? – 2012-03-23 14:49:10

相關問題