2016-03-07 40 views
2

我有這樣一類重載兩個不同的I/O操作:我如何在C++

MyClass { 
public: 
    int a; 
    unsigned char b,c,d; 
    size_t e,f; 
    double g, h; 
    friend ostream& operator<< (ostream& os, const MyClass& mc) { 
     os<<mc.a<<mc.b<<mc.c<<mc.d<<mc.e<<mc.f<<mc.g<<mc.h; 
     return os; 
    } 
}; 

我已經超載了<<運營商,但我也希望再<<情況下,我怎麼能重載兩個不同<<運營商?

我想這:

MyClass { 
public: 
    int a; 
    unsigned char b,c,d; 
    size_t e,f; 
    double g, h; 
    friend ostream& operator<< (ostream& os, const MyClass& mc, int type) { 
     if(type==1){ 
      os<<mc.a<<mc.b<<mc.c<<mc.d<<mc.e<<mc.f<<mc.g<<mc.h; 
      return os; 
     } else if(type==2){ 
      os<<mc.a<<mc.c<<mc.d<<mc.e<<mc.g; 
      return os; 
    } 
}; 

但沒有工作,Too many arguments for this operator function

我該怎麼辦?

+4

你究竟在做什麼?第二個重載會解決什麼問題?你能告訴我們你想如何使用輸出操作符嗎?另外,請閱讀關於[XY問題](http://xyproblem.info/),這與您的問題非常相關。 –

+0

那麼,你的鏈接是有幫助的。在我的問題中,我想在兩個階段寫'MyClass'。在第一階段,我需要存儲一些額外的信息,比如'b','f','h',然後,我合併所有臨時文件並存儲'a','c','d','e', 'g'。所以,如果有兩個'<<'的情況,它會很方便。謝謝。 – user1024

+0

「MyClass」的「type1」和「type2」實例,它們有多獨特?是否可以通過創建兩個類來解決:'MyClass2'具有'a','c','d'和'g'成員,然後是從MyClass2繼承的MyClass1並添加對其他類的支持成員? –

回答

1

我修改了這個類,並決定保留原始答案以供參考。現在這個版本在設計上更加優雅;然而,如果我使用我的錯誤處理程序/記錄器庫,它可能會更清潔,但將它們包含在這個答案中是爲了適合這裏的一個規模,但主函數將設置在try catch塊中,並且我的錯誤處理程序和記錄器可以在錯誤非常嚴重的情況下拋出錯誤並退出程序,或者如果值無效但將程序的操作仍然處於可接受的狀態以繼續,則可以將消息記錄到控制檯窗口或文件。

該類有點臃腫,錯誤消息通常不需要存在,但用作演示以顯示正確的程序邏輯流程。

這裏是我對user1024所說的更新的類和主函數,它解決了根據字段值設置布爾標誌變量的問題,而不是調用哪個函數。現在,他可以擁有未初始化爲類的默認值,然後使用相同的默認值初始化類。該類的狀態現在基於函數調用而不是成員值。

Temp.h

#ifndef TEMP_H 
#define TEMP_H 

class Temp { 
    friend std::ostream& operator<<(std::ostream& os, const Temp& t); 
private: 
    int m_a, m_b, m_c; 
    double m_d, m_e, m_f; 

    bool m_isInitialized; 
    bool m_updated; 

    const std::string m_strInitMessage = std::string("First stage values must be initalized before calling this funciton.\n"); 
    const std::string m_strUpdateMessage = std::string("setUpdateStage needs to be called first before modifying this value.\n"); 
public: 
    Temp(); 
    Temp(int a, int b, int c); 
    Temp(int a, int b, int c, double d, double e, double f); 

    void setInitialStage(int a, int b, int c); 
    void setUpdateStage(double d, double e, double f); 

    bool isInitialized() const; 
    bool isUpdated() const; 

    int  getA() const; 
    int  getB() const; 
    int  getC() const; 

    // These Are Updating Functions Not Setting Functions setInitialStage Must Be Called First 
    void updateA(int a); 
    void updateB(int b); 
    void updateC(int c); 

    double getD() const; 
    double getE() const; 
    double getF() const; 

    // These Are Updating Functions Not Setting Functions Both setInitialStage & setUpdateStage Must Be Called First 
    void updateD(double d); 
    void updateE(double e); 
    void updateF(double f); 

private: 
    // Helper Function 
    bool testStages(); 

}; // Temp 

#endif // TEMP_H 

Temp.cpp

#include "stdafx.h" 
#include "Temp.h" 

std::ostream& operator<<(std::ostream& os, const Temp& t) { 
    if (t.isUpdated()) { 
     os << t.getA() << " " << t.getB() << " " << t.getC() << " " 
      << t.getD() << " " << t.getE() << " " << t.getF() << std::endl; 
     return os; 
    } else { 
     os << t.getA() << " " << t.getB() << " " << t.getC() << std::endl; 
     return os; 
    } 

} // operator<< 

Temp::Temp() : 
m_a(0), 
m_b(0), 
m_c(0), 
m_d(0), 
m_e(0), 
m_f(0), 
m_isInitialized(false), 
m_updated(false) { 
} // Temp 

Temp::Temp(int a, int b, int c) : 
m_a(a), 
m_b(b), 
m_c(c), 
m_d(0.0), 
m_e(0.0), 
m_f(0.0), 
m_isInitialized(true), 
m_updated(false) { 
} // Temp 

Temp::Temp(int a, int b, int c, double d, double e, double f) : 
m_a(a), 
m_b(b), 
m_c(c), 
m_d(d), 
m_e(e), 
m_f(f), 
m_isInitialized(true), 
m_updated(true) { 
} // Temp 

void Temp::setInitialStage(int a, int b, int c) { 
    // Do Nothing With 2nd Stage Variables And Update Flag 

    if (!m_isInitialized) { 
     m_a = a; 
     m_b = b; 
     m_c = c; 
     m_isInitialized = true; 
    } else { 
     // Do not Reinitalize 
     std::cout << "Initial stage values are already initialized, please use the individual update functions.\n"; 
     return; 
    } 
} // setInitialStage 

void Temp::setUpdateStage(double d, double e, double f) { 
    // Check To See If This Has Been Intialized First 
    if (!m_isInitialized) { 
     std::cout << "\nFirst Stage values must be initialized first\n"; 
     return; 
    } else { 
     if (!m_updated) { 
      // Do nothing with Initial Values 
      m_d = d; 
      m_e = e; 
      m_f = f; 
      m_updated = true; 
     } else { 
      // Do Not Reinitalize 
      std::cout << "Update stage values have already been initialized, please use the individual update functions.\n"; 
      return; 
     } 
    } 
} // setUpdateStage 

bool Temp::isInitialized() const { 
    return m_isInitialized; 
} // isInitialized 

bool Temp::isUpdated() const { 
    return m_updated; 
} // isUpdated 

int Temp::getA() const { 
    if (!m_isInitialized) { 
     std::cout << "m_a has not been initialized\n"; 
     return 0; 
    } 
    return m_a; 
} // getA 

int Temp::getB() const { 
    if (!m_isInitialized) { 
     std::cout << "m_b has not been initialized\n"; 
     return 0; 
    } 
    return m_b; 
} // getB 

int Temp::getC() const { 
    if (!m_isInitialized) { 
     std::cout << "m_c has not been initialized\n"; 
     return 0; 
    } 
    return m_c; 
} // getC 

void Temp::updateA(int a) { 
    if (!m_isInitialized) { 
     std::cout << m_strInitMessage; 
     return; 
    } 
    m_a = a; 
} // updateA 

void Temp::updateB(int b) { 
    if (!m_isInitialized) { 
     std::cout << m_strInitMessage; 
     return; 
    } 
    m_b = b; 
} // updateB 

void Temp::updateC(int c) { 
    if (!m_isInitialized) { 
     std::cout << m_strInitMessage; 
     return; 
    } 
    m_c = c; 
} // updateC 

double Temp::getD() const { 
    if (!m_updated) { 
     std::cout << "m_d has not been initialized\n"; 
     return 0; 
    } 
    return m_d; 
} // getD 

double Temp::getE() const { 
    if (!m_updated) { 
     std::cout << "m_e has not been initialized\n"; 
     return 0; 
    } 
    return m_e; 
} // getE 

double Temp::getF() const { 
    if (!m_updated) { 
     std::cout << "m_f has not been initialized\n"; 
     return 0; 
    } 
    return m_f; 
} // getF 

bool Temp::testStages() { 
    if (!m_isInitialized) { 
     std::cout << m_strInitMessage; 
     return false; 
    } else { 
     if (!m_updated) { 
      std::cout << m_strUpdateMessage; 
      return false; 
     } 
    } 
    return true; 
} // testStages 

void Temp::updateD(double d) { 
    if (!testStages()) { 
     return; 
    } 
    m_d = d; 
} // updateD 

void Temp::updateE(double e) { 
    if (!testStages()) { 
     return; 
    } 
    m_e = e; 
} // updateE 

void Temp::updateF(double f) { 
    if (!testStages()) { 
     return; 
    } 
    m_f = f; 
} // update 

的main.cpp

#include "stdafx.h" 
#include "Temp.h" 

int main() { 

    Temp t1; 
    std::cout << "Default constructor called." << std::endl; 
    std::cout << t1 << std::endl; 

    // Error Cases 
    std::cout << "Error Cases For Default Constructor Before setInitialStage is called:" << std::endl; 
    std::cout << "---------------------------------------------------------------------" << std::endl; 
    std::cout << "Trying to update a first stage value before setInitialStage is called." << std::endl; 
    t1.updateA(1); 
    std::cout << t1 << std::endl; 
    std::cout << "Trying to update a second stage value before setInitialStage is called." << std::endl; 
    t1.updateD(2.3); 
    std::cout << t1 << std::endl; 
    std::cout << "Trying to call setUpdateStage before m_isInitialized = true" << std::endl; 
    t1.setUpdateStage(4.5, 6.7, 8.9); 
    std::cout << t1 << std::endl; 

    // 1st Stage Initialization WRT To Using A Default Constructor 
    std::cout << "After setInitalStage is called" << std::endl; 
    t1.setInitialStage(1, 2, 3); 
    std::cout << t1 << std::endl; 

    // Error Cases 
    std::cout << "Error Cases For Default Constructor After setInitialStage is called:" << std::endl; 
    std::cout << "--------------------------------------------------------------------" << std::endl; 
    std::cout << "Calling setInitialStage after it has already been called." << std::endl; 
    t1.setInitialStage(4, 5, 6); 
    std::cout << t1 << std::endl; 
    std::cout << "Trying to update a second stage value after setInitialStage and before setUpdateStage have been called." << std::endl; 
    t1.updateD(7.8); 
    std::cout << t1 << std::endl; 

    std::cout << "Updating a first stage value after setInitialStage is called." << std::endl; 
    t1.updateB(9); 
    std::cout << t1 << std::endl; 

    std::cout << "Calling setUpdatedStage." << std::endl; 
    t1.setUpdateStage(10.11, 12.13, 14.15); 
    std::cout << t1 << std::endl; 

    // Error Case 
    std::cout << "Error Case For Default Constructor After Both\n setInitialStage & setUpdateStage have been called." << std::endl; 
    std::cout << "------------------------------------------------" << std::endl; 
    std::cout << "Calling setUpdateStage after it has already been called." << std::endl; 
    t1.setUpdateStage(16.17, 18.19, 20.21); 
    std::cout << t1 << std::endl; 

    std::cout << "Updating second stage value afer both setInitializeStage & setUpdateStage have been called." << std::endl; 
    t1.updateF(22.23); 
    std::cout << t1 << std::endl << std::endl; 

    Temp t2(1, 2, 3); 
    std::cout << "First stage constructor called" << std::endl; 
    std::cout << t2 << std::endl; 

    // Error Cases 
    std::cout << "Error Cases For 1st Stage Constructor" << std::endl; 
    std::cout << "-------------------------------------" << std::endl; 
    std::cout << "Calling setInitialStage after using this constructor." << std::endl; 
    t2.setInitialStage(4, 5, 6); 
    std::cout << t2 << std::endl; 

    std::cout << "Trying To Update Second Stage Value Before setUpdateStage is called." << std::endl; 
    t2.updateD(7.8); 
    std::cout << t2 << std::endl; 

    std::cout << "Updating 1st Stage Value" << std::endl; 
    t2.updateB(9); 
    std::cout << t2 << std::endl; 

    std::cout << "Calling setUpdateStage" << std::endl; 
    t2.setUpdateStage(10.11, 12.13, 14.15); 
    std::cout << t2 << std::endl; 

    // Error Case 
    std::cout << "Error Case For 1st Stage Constructor After setUpdateStage has been called." << std::endl; 
    std::cout << "-------------------------------------------------------------------------" << std::endl; 
    t2.setUpdateStage(16.17, 18.19, 20.21); 
    std::cout << t2 << std::endl; 

    std::cout << "Updating 2nd stage value." << std::endl; 
    t2.updateE(22.23); 
    std::cout << t2 << std::endl << std::endl; 


    Temp t3(1, 2, 3, 4.5, 6.7, 8.9); 
    std::cout << "Full Stage Constructor Called" << std::endl; 
    std::cout << t3 << std::endl; 

    // Error Cases 
    std::cout << "Error Cases For Full Stage Constructor:" << std::endl; 
    std::cout << "---------------------------------------" << std::endl; 
    std::cout << "Calling setInitialStage" << std::endl; 
    t3.setInitialStage(10, 11, 12); 
    std::cout << t3 << std::endl; 
    std::cout << "Calling setUpdateStage" << std::endl; 
    t3.setUpdateStage(13.14, 15.16, 17.18); 
    std::cout << t3 << std::endl; 

    std::cout << "Updating 1st & 2nd Stage Values" << std::endl; 
    t3.updateA(19); 
    t3.updateD(20.21); 
    std::cout << t3 << std::endl; 

    std::cout << "With this design 0 is now an acceptable value." << std::endl; 
    std::cout << "Updating all of t3's values." << std::endl; 
    t3.updateA(0); 
    t3.updateB(0); 
    t3.updateC(0); 
    t3.updateD(0); 
    t3.updateE(0); 
    t3.updateF(0); 
    std::cout << t3 << std::endl; 

    std::cout << "Using Default Constructor To Show That Both stageFunctions Can accept 0 as value" << std::endl; 
    Temp t4; 
    std::cout << "Unitialized:" << std::endl 
       << t4 << std::endl; 

    std::cout << "Calling setInitialStage" << std::endl; 
    t4.setInitialStage(0, 0, 0); 
    std::cout << t4 << std::endl; 
    std::cout << "Calling setUpdateStage" << std::endl; 
    t4.setUpdateStage(0, 0, 0); 
    std::cout << t4 << std::endl; 


    std::cout << std::endl; // Used As A Break Point Before Application End 

    return 0; 
} // main 

利用具有3構建此類您可以通過以下三種方式創建此類:創建一個空的未初始化版本,以便稍後填寫所有部分,第一階段在施工時設置,以便稍後更新第二階段,最後完成施工過程中的所有階段。這也表明,所有3個構造函數,所有初始化函數,更新函數和getter都通過相同std::ostream << operator工作。它還演示瞭如何按特定順序調用特定函數,並演示何時不調用特定函數重複次數。我相信還有很多其他方法可以實現,但能夠看到以幾種成功方式完成相同任務的優點。

+0

這個答案確實更優雅!我非常感謝你的幫助!我會接受你的回答。 – user1024

+0

@ user1024如果我只能分享我的錯誤處理 - 記錄器庫... –

1

您不能有兩個具有相同簽名的函數,並且您發現無法向此運算符重載添加其他參數。

這編譯,但我reccommend你找到另一種設計,因爲這是一個可憎

#include <iostream> 

class MyClass 
{ 

}; 

std::ostream& operator<<(std::ostream& os, const MyClass& myClass) { return os; } 
std::ostream& operator<<(std::ostream& os, MyClass& myClass) { return os; } 
1

Temp.h

#ifndef TEMP_H 
#define TEMP_H 

class Temp { 
    friend std::ostream& operator<<(std::ostream& os, const Temp& t); 
private: 
    int m_a; 
    double m_b; 

    bool m_updated; 

public: 
    Temp(); 
    explicit Temp(int a, double b = 0); 

    int  getA() const; 
    void setA(int a); 
    double getB() const; 
    void setB(double b); 

    bool isUpdated() const; 

}; // Temp 

#endif // TEMP_H 

Temp.cpp

#include "stdafx.h" 
#include "Temp.h" 

std::ostream& operator<<(std::ostream& os, const Temp& t) { 
    if (t.isUpdated()) { 
     os << t.getA() << " " << t.getB(); 
     return os; 
    } else { 
     os << t.getA(); 
     return os; 
    } 

} // operator<< 

Temp::Temp() : 
m_a(0), 
m_b(0), 
m_updated(false) { 
} // Temp 

Temp::Temp(int a, double b) : 
m_a(a), 
m_b(b), 
m_updated(false) { 
    if (m_b != 0) { 
     m_updated = true; 
    } 
} // Temp 

int Temp::getA() const { 
    return m_a; 
} // getA 

void Temp::setA(int a) { 
    m_a = a; 
} // setA 

double Temp::getB() const { 
    return m_b; 
} // getB 

void Temp::setB(double b) { 
    m_b = b; 
    if (m_b != 0) { 
     m_updated = true; 
    } 
} // setB 

bool Temp::isUpdated() const { 
    return m_updated; 
} // isUpdated 

的main.cpp

#include "stdafx.h" 
#include "Temp.h" 

int main() { 
    Temp t1(3); 

    std::cout << "Before Updated" << std::endl; 
    std::cout << t1 << std::endl << std::endl; 

    std::cout << "After Updated" << std::endl; 
    t1.setB(4.2); 
    std::cout << t1 << std::endl << std::endl; 

    Temp t2(7, 12.5); 

    std::cout << "Updated Values During Construction" << std::endl; 
    std::cout << t2 << std::endl; 


    std::cout << std::endl; 

    return 0; 
} // main 

std::ostream << operator不會讓你在3個值傳遞,它需要一個ostream對象,希望對象傳遞給它。所以我在這裏做的是我創建了一個具有默認構造函數的類以及最後一個參數是可選的顯式構造函數。現在這也需要該類保持1個額外的變量,一個布爾類型。該布爾類型跟蹤查看可選參數是否在初始構造函數期間或通過更新函數或設置函數進行更新。然後,當這個類對象與std::ostream << operator一起使用時,它首先檢查這個布爾值是true還是false,然後從那裏分支到它應該使用的流類型。

現在,當你開始和你的班級一起工作時,你必須考慮;更新值是以兩個直接階段發生的嗎?或者可以一次更新一個?預先了解這一點很重要。如果您知道多個變量將在稍後或第二階段添加或更新到您的課程中,那麼我提供的方法將起作用並且管理起來很簡單。

現在,如果您在兩個以上的多個階段一次添加組件1,則此方法變得更加複雜。現在,我已經展示的示例類中的設計過程存在一個缺陷。設計上的缺陷是:如果0是m_b的可接受答案呢?那麼這種更新方法在這種情況下將不起作用,因爲該類將表明它沒有更新,並且不會輸出第二個字段。這是要考慮的事情。

一個可能的解決辦法是按照我提供的方法做同樣的設計方法,但要將所有初始值都作爲基本數據類型,並且要在第二階段中添加所有參數以指向他們的類型。那麼這樣你就可以根據指針是否有值或者是nullptr來設置你的m_updated

但是,此代碼確實演示了使用單個std::ostream << operator調用來分支不同的std::ostream << operators的一種方法。

編輯

另一種可能的解決方案,而不是用在你的班上一個布爾值是使用你的類內的枚舉是這樣的:

class SomeClass { 
public: 
    enum Stage { 
     S_1 = 1, 
     S_2, 
     S_3, 
     S_LAST, 
    }; 

private: 
    Stage m_stage; 

public: 
    Stage getStage() const { return m_stage; } 
}; 

然後,當你構造器類有默認類型; m_stage將被設置爲S_1,然後當您執行特定的更新組時,可以在std::ostream << operator方法中執行多個階段,而不是使用帶有bool的if語句,可以使用基於類的switch和case語句階段,並且在switch語句中,默認情況可以是第一階段或錯誤情況。

+0

哇,你的答案是我想要的,'m_updated'成員真的很有幫助,我可以檢查'm_updated'的值並在'<<'中做我想要的。 「SomeClass」是一種更普遍的方式。謝謝! – user1024

+0

@ user1024是的,如果你有類似的情況,你可能有兩個以上的階段,後面的方法可以在類枚舉中使用,並使用switch語句而不是使用帶有bool變量的if語句。 –

+0

@ user1024另外,請記住,如果您最初使用它並且0是'm_b'的可接受值,它將默認爲'false',並且它不會顯示0或顯示該變量或字段存在。只是需要考慮。 –