当前位置: 首页 > 知识库问答 >
问题:

C 11返回语句中的显式转换运算符/构造函数

戎桐
2023-03-14

我有一个下面的例子(布尔类型过于安全):

#include <cstdlib>

struct boolean_type
{

    explicit
    boolean_type(bool _value)
        : value_(_value)
    { ; }

    explicit
    operator bool () const
    {
        return value_;
    }

private :

    bool value_;

};

struct A
{

    A(int const _i) 
        : i_(_i)
    { ; }

    boolean_type operator == (A const & _other) const
    {
        return (i_ == _other.i_);
    }

private :

    int i_;

};

bool t()
{
    return A(0) == A(0);
}

int main()
{ 
    return EXIT_SUCCESS;
}

众所周知,这样的代码包含一个错误:“无法转换’((int)((const A*)this)-

我想说:

由于指定的障碍,我不能简单地将bool的所有条目替换为我的用户代码中的超级安全的boolean_type(这是mocked-对象),因为,例如,在的返回语句中,提升::变体::操作符==使用了上述构造,将其视为隐式转换。类似的障碍并不唯一。

共有2个答案

高功
2023-03-14

为什么在这两种情况下都没有显式转换?

因为如果您想要显式转换,那么程序员就有责任显式化。

在这种情况下,如果您允许隐式转换,那么隐式转换将起作用。但当您将运算符bool布尔类型::布尔类型标记为显式时,不允许使用它们。

为什么是含蓄的?

因为你没有写转换。你必须:

  boolean_type operator == (A const & _other) const
  {   
      return boolean_type (i_ == _other.i_);
  }

...以及:

bool t()
{   
    return (bool) (A(0) == A(0));
}

但是这里有什么风险呢?

你告诉我们<代码>显式专门用来告诉编译器,允许进行某些隐式转换可能存在风险。因此,当您将这些函数标记为显式时,您对编译器说:

好吧,如果你允许从bool到boolean_操作符的隐式转换,或者反之亦然,可能会发生不好的事情。所以不要允许这些隐式转换。

你没有告诉编译器(或我们)为什么那些隐式转换是危险的。你只是说它们是。

丁豪
2023-03-14

你有两个隐式转换。一个在这里:

return (i_ == _other.i_);

另一个在这里:

return A(0) == A(0);

这些是隐式的,因为您没有显式地告诉编译器您想要将比较的结果分别转换为boolean_typebool。这些隐式转换是不允许的,因为您使boolean_type显式的构造函数和转换运算符-这就是显式关键字的全部意义。

你需要做:

return static_cast<boolean_type>(i_ == _other.i_);

以及:

return static_cast<bool>(A(0) == A(0));

将转换为bool显式的典型原因是,转换可能会在您不打算使用它的情况下使用。例如,如果您有名为b1b2的对象,并且具有非显式的转换,则可以执行以下操作:

b1 > 0
b1 == b2

这些可能不是布尔转换运算符的预期用途。

 类似资料:
  • 但是,如果删除转换构造函数“fraction(int nn):nom(nn),den(1){}”或转换运算符“operator double()const{return double(nom)/den;}”,程序运行良好。 我想把分数转换成分数和分数。我可以做什么来既有转换,又有程序编译?

  • CLANG6、CLANG7和gcc 7.1、7.2和7.3都同意以下代码是有效的C++17代码,但在C++14和C++11下有歧义。MSVC2015和2017也接受它。然而,即使在C++17模式下,GCC-8.1和8.2也拒绝了它: 接受它的编译器选择模板化的显式转换函数。 拒绝它的编译器同意在以下两个方面存在歧义: null 以下是来自(接受代码)的错误:

  • 问题内容: 以Oracle论坛中显示的示例:使用plsql生成excel(xls),我想从查询的数据集中生成一个excel文件。 此处提供的示例有效。但是,我遇到了一些挑战: 我的SQL查询很长,超过了4000个字符的限制。 我想将参数传递给我的查询。 我想以一种非常简单的方式做到这一点,并且不使用Dynamic SQL(如果可能)。 我提出的内容如下: 包装定义: 现在,我的匿名阻止最好是如下所

  • 问题内容: 要从Java 类中创建新对象,通常使用以下语句 我读过new运算符通过在堆中分配内存空间来创建新对象,但是我也读到调用构造函数会创建它。因此,这有点令人困惑。哪一个在创建对象?是 新 运算符还是默认构造函数? 问题答案: 具有与类同名的方法是合法的(尽管令人困惑),消除了任何歧义。指示JVM应该为给定的类和参数列表调用实例初始化方法,并返回已初始化的对象(在初始化方法的第一个(隐藏)参

  • 问题内容: 我发现Java编译对于使用int和float的赋值和自赋值语句具有非预期的行为。 以下代码块说明了该错误。 在自赋值中,编译不会发出错误,但是求和的结果是带有值的int ,并且变量保持值。 在表达式中,编译器会发出一条错误消息 “错误:可能丢失精度” 。 有人可以解释这种行为。 编辑:我已经将此代码块发布在https://compilr.com/cguedes/java-autoass