2016-03-07 23 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或显示该变量或字段存在。只是需要考虑。 –