【问题标题】:Implicit type conversion for user-defined type用户定义类型的隐式类型转换
【发布时间】:2020-03-15 17:27:08
【问题描述】:

为什么下面源码中没有对自定义类型进行隐式类型转换?

到类型 A 的隐式类型转换应该在注释行发生,但它没有发生,并且在该行发生错误。

我想知道这个错误的语法规则和解决方法。

#include <iostream>

using namespace std;

class A {
   int v;
public:
    A(int _v): v(_v) {}
    operator int (void) const {
        return v;
    }
    friend ostream& operator << (ostream& os, const A& s) {
        return os << "A: " << s.v;
    }   
};

class B {
    int x, y;   
public:
    B(int _x, int _y): x(_x), y(_y) {}
    operator A(void) const {
        return A(x+y);
    }
};

int main(void)
{
    B b(1,2);
    cout << A(b) << endl;
    cout << (A)b << endl;
    cout << b << endl;     // error --> why?
    return 0;
}

--> 附加问题

感谢 Sam Varshavchik 的回复。

如下定义A类解决了这个问题。

class A {
   int v;
public:
    A(int _v): v(_v) {}
    operator int (void) const {
        return v;
    }
    friend ostream& operator << (ostream& os, const A& s);
};

ostream& operator << (ostream& os, const A& s){
    return os << "A: " << s.v;
}

//////////////

class A {
   int v;
public:
    A(int _v): v(_v) {}
    operator int (void) const {
        return v;
    }
    friend ostream& operator << (ostream& os, const A& s){
        return os << "A: " << s.v;
    }
};

ostream& operator << (ostream& os, const A& s);

是否将“operator

【问题讨论】:

  • 我知道你要去哪里了,你可能已经知道了,但是对于未来的读者,小心 C 风格的演员 (A)b。无论是否有意义,C 风格的演员都会以A 威胁b。这里说得通。并非总是如此。这将是static_cast 的好地方。 static_cast 确保演员阵容合理。
  • 错误信息是什么?提示:它可能表示转换不明确。
  • 我在实际开发过程中也使用了static_cast。希望看到这段代码的同学能记住user4581301的忠告。但是,如果您仍然不了解 static_cast,您可以跳过他的建议。此代码仅供初学者使用。
  • 致Pete Becker:这不是由于转换模糊而导致的错误。感谢您的关注。

标签: c++ types implicit user-defined


【解决方案1】:

这一定与有关重载决议、友元函数、隐式转换之间关系的神秘规则有关。因为这不仅仅是隐式转换,这里。您还定义了一个重载operator&lt;&lt;,它是一个友元函数。

通过简单地去掉友元函数,下面的代码在 gcc 9.2 上编译得很好。 get rid of using namespace std;, as well 也无妨:

#include <iostream>

class A {
   int v;
public:
    A(int _v): v(_v) {}
    operator int (void) const {
        return v;
    }
};

std::ostream& operator << (std::ostream& os, const A& s) {
    return os << "A: " << (int)s;
}

class B {
    int x, y;
public:
    B(int _x, int _y): x(_x), y(_y) {}
    operator A(void) const {
        return A(x+y);
    }
};

int main(void)
{
    B b(1,2);
    std::cout << A(b) << std::endl;
    std::cout << (A)b << std::endl;
    std::cout << b << std::endl;     // No more error
    return 0;
}

【讨论】:

  • 对所有对象使用“std ::”会增加代码的长度,使其可读性降低。我认为省略标准库的命名空间“std”对可读性有好处,即使省略了其他命名空间。
  • 我是否应该在 stackoverflow.com 上为您找到一些问题,其中有人被一个完全无法理解的编译错误完全弄糊涂了,其唯一的原因是 using namespace std;?多年来,我一直在回答他们……Here's one。欢迎您在事先不知道的情况下,尝试找出编译错误的原因是什么。
  • 您不必再为我查找这些问题。我认为每次类似错误的答案都会让你感到疲倦。我认为你是一个很好的人,为犯下这样的错误而感到抱歉,并试图不让它发生。你的努力肯定会帮助世界发展。
  • 但是,即使初学者很容易出错,提高代码的可读性也很重要。即使您的问题被一些初学者对名称空间的不成熟使用所淹没,不利用 C++ 语法似乎也不是一个聪明的主意。相反,这是向他们解释如何正确使用命名空间的更好方法。
【解决方案2】:

在类中定义友元函数时,只能通过 ADL 找到。

在您的前两行中,您提供了一个A,因此 ADL 启动并找到了operator&lt;&lt;。传递 B ADL 时将无助于找到您的 operator&lt;&lt;,因此编译器从不考虑转换。

更多关于ADL的细节。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 2012-01-21
    • 2011-05-08
    • 1970-01-01
    相关资源
    最近更新 更多