1

我正在处理一个带有矩阵的项目,但我遇到了重载运算符的问题。

我已经声明了这些用户友好的输入/输出函数:

friend std::istream& operator>>(std::istream& is, MathMatrix& m); //keyboard input
friend std::ostream& operator<<(std::ostream& os, const MathMatrix& m); // screen output
friend std::ifstream& operator>>(std::ifstream& ifs, MathMatrix& m); // file input
friend std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m); // file output

在定义最后一个时,在这段简单的代码中,我得到了一个错误并且无法编译:

// file output
std::ofstream& operator<<(std::ofstream& ofs, const MathMatrix& m) {
    //put matrix dimension in first line
    ofs << m.n << std::endl;
    //put data in third line
    for (int i=0; i<m.n; i++) {
        for (int j=0; j<m.n; j++) ofs << m(i,j) << " ";
        ofs << std::endl;
    }
    return ofs;
}

错误在ofs << m.n(和类似的ofs << m(i,j))中。它说:

const MathMatrix &m
Error: more than one operator "<<" matches these operands:
    function "operator<<(std::ofstream &ofs, const MathMatrix &m)"
    function "std::basic_ostream<_Elem, _Traits>::operator<<(int _Val) [with _Elem=char, _Traits=std::char_traits<char>]"
    operand types are std::ofstream << const int

过了一会儿,我想也许问题是我有一个MathMatrix类似的构造函数MathMatrix (int n),所以编译器可能试图从转换int nMathMatrix(int n). 我不明白它为什么会这样做,但鉴于 IDE 给出的解释,这是我能想到的唯一解释。

你能看到我错过了什么吗?你知道如何解决吗?

4

2 回答 2

2

如果在您的类中,您有一个具有与您的类不同类型的单个参数的构造函数,则它可用于隐式类型转换。为防止这种情况发生,您只需将该构造函数标记为显式:

class MathMatrix {
public:
   explicit MathMatrix( int m );
...
};

始终将单参数构造函数标记为显式是一个好主意(除非参数是相同的类类型或者您确实想要这种类型转换)

于 2013-10-17T18:02:24.760 回答
2

重载决议中有一个微妙之处,导致在为 call 选择函数之间存在歧义ofs << m.n。这是一个重现问题的简短示例:

struct Base
{
    void operator<<(int);
};

struct Derived : Base
{
};

struct converter
{
    converter(int);
};

void operator<<(Derived&, converter const&);

int main()
{
    const int i = 42;
    Derived d;
    d << i;
}

为什么通话模棱两可?

首先,成员函数Base::operator<<获得一个额外的类型参数,Base&仅用于重载解析 [over.match.funcs]/2

候选函数集可以包含要针对同一参数列表解析的成员函数和非成员函数。为了使参数和参数列表在这个异构集合中具有可比性,成员函数被认为有一个额外的参数,称为隐式对象参数,它表示已调用成员函数的对象。

由于成员函数(甚至继承于Derived)是 的成员函数Base,所以参数类型是 a Base&,而不是 a Derived;见 /4。

因此我们比较

void operator<<(Base&, int);                  // #0
void operator<<(Derived&, converter const&);  // #1

调用的参数d << i类型为Derived(lvalue) 和const int. 所以:

  1. 对于过载 #0
    1. 对于第一个参数,需要进行派生到基础的转换
    2. 对于第二个参数,需要进行资格转换(const intto int
  2. 对于过载 #1
    1. 对于第一个参数,完全匹配(无转换)
    2. 对于第二个参数,需要进行限定转换,然后进行用户定义的转换(const intto intintto converter

转换 1.1 比转换 2.1 差,但转换 1.2 比转换 2.2 好。因此,调用是模棱两可的。


如何解决歧义?

任何一个:

  • (首选)进行MathMatrix显式转换
  • 只声明一个operator<<(std::ostream&, MathMatrix const&),但没有声明std::ofstream(这将使 1.1 等于 1.2,因此重载 #1 成为更好的匹配)
  • std::ofstream调用中的 显式转换为基类std::ostream(与以前的版本类似)
  • 隐藏有问题的重载,例如通过使用声明 using std::operator<<;
于 2013-10-17T18:34:17.123 回答