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

三元运算符隐式转换为基类

令狐唯
2023-03-14

考虑这段代码:

struct Base
{
    int x;
};

struct Bar : Base
{
    int y;
};

struct Foo : Base
{
    int z;
};

Bar* bar = new Bar;
Foo* foo = new Foo;

Base* returnBase()
{
    Base* obj = !bar ? foo : bar;
    return obj;
}

int main() {
    returnBase();
    return 0;
}

这在Clang或GCC下不起作用,给我:

错误:不同指针类型“Foo*”和“Bar*”之间的条件表达式缺少强制转换Base*obj=!酒吧foo:bar;

这意味着要编译它,我必须将代码更改为:

Base* obj = !bar ? static_cast<Base*>(foo) : bar;

既然存在到< code>Base*的隐式转换,那么是什么阻止了编译器这样做呢?

换句话说,为什么Base*obj=foo不使用强制转换,但使用?:操作员没有?是因为我不清楚我想使用Base部件吗?

共有3个答案

李星波
2023-03-14

换句话说,为什么Base*obj=foo不使用强制转换,但使用?:操作员没有?

条件表达式的类型不取决于它被分配给什么。在您的情况下,编译器需要能够评估!bar? foo: bar;,而不管它被分配给什么。

在您的情况下,这是一个问题,因为转换为bar类型的foobar都不能转换为foo类型。

是因为不清楚我想使用基础部件吗?

精确地

龚俭
2023-03-14

允许条件运算符转换为基指针类型听起来不错,但在实践中会有问题。

在您的示例中

struct Base {};
struct Foo : Base {};
struct Bar : Base {};

这似乎是对 cond 类型的明显选择? foo : 酒吧Base*

但这种逻辑不适用于一般情况

例如。:

struct TheRealBase {};
struct Base : TheRealBase {};
struct Foo : Base {};
struct Bar : Base {};

应该< code>cond吗?foo : bar是属于< code>Base*类型还是属于< code > realbase * 类型?

怎么样:

struct Base1 {};
struct Base2 {};
struct Foo : Base1, Base2 {};
struct Bar : Base1, Base2 {};

cond应该是什么类型?foo:bar现在是吗?

或者现在怎么样:

struct Base {};

struct B1 : Base {};
struct B2 : Base {};

struct X {};

struct Foo : B1, X {};
struct Bar : B2, X {};


      Base
      /  \
     /    \   
    /      \
  B1        B2 
   |   X    |
   | /   \  |
   |/     \ |
  Foo      Bar

     
      

哎哟!!祝你好运推理出一种类型的cond?foo: bar。我知道,丑陋,丑陋,不实用,值得猎杀,但标准仍然必须对此有规则。

你明白了。

还要记住,std::common_type是根据条件运算符规则定义的。

嗯……这些都是很好的例子,说明由于模糊性而无法工作的情况。但C语言有许多转换规则,只要转换明确,它们就可以工作。就像这个问题。不

在这里只允许明确的例子将是极其有问题的。添加基类的简单操作可能会使程序不可编译:

初始代码库:

struct Base {};
struct Foo : Base {};
struct Bar : Base {};

这将允许 __ ? foo : 酒吧; 被写入。现在您无法修改继承结构,因为几乎任何修改都会破坏以合法方式使用三元运算符的现有代码:

struct FooBarCommon {};

struct Base {};
struct Foo : Base, FooBarCommon {};
struct Bar : Base, FooBarCommon {};
struct Baz : Base {};

这似乎是一个合理的修改。按照现在的规则,只要不修改类的公共 API,就可以执行此操作。这将不再是真的,标准将只允许在明确的情况下转换为基类。

沈琨
2023-03-14

引用C标准草案N4296,第5.16节条件运算符,第6.3段:

  • 第二个和第三个操作数中的一个或两个都具有指针类型;执行指针转换(4.10)和限定转换(4.4)以将它们带到它们的复合指针类型(第5条)。结果是复合指针类型。

第5节表述,第13.8和13.9段:

分别具有T1和T2类型的两个操作数p1和p2的复合指针类型,其中至少一个是指向成员类型或std::nullptr_t的指针或指针,为:

  • 如果T1和T2是相似的类型(4.4),则T1和T2的cv组合类型;
  • 否则,需要确定复合指针类型的程序将形成错误。

注意:我在这里复制了5/13.8,只是为了向你展示它没有命中。实际上实际上是5/13.9,“程序格式不正确”。

第4.10节指针转换,第3段:

“指向cv D的指针”类型的prvalue,其中D是一个类类型,可以转换为“指向cv B的指针”类型的prvalue,其中B是D的基类(第10条)。如果B是D的不可访问的(第11条)或不明确的(第10.2条)基类,则需要这种转换的程序是病态的。转换的结果是指向派生类对象的基类子对象的指针。空指针值被转换为目标类型的空指针值。

因此,Foo和Bar都派生自同一个基类并不重要。重要的是指向Foo的指针和指向Bar的指针不能相互转换(没有继承关系)。

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

  • 条件(三元)运算符是 JavaScript 仅有的使用三个操作数的运算符。一个条件后面会跟一个问号(?),如果条件为 truthy ,则问号后面的表达式A将会执行;表达式A后面跟着一个冒号(:),如果条件为 falsy ,则冒号后面的表达式B将会执行。本运算符经常作为 if 语句的简捷形式来使用。(MDN) 三元运算符,也称条件运算符、三目运算符。 三元运算符可以代替简单的 if 语句。 1. 语

  • 问题内容: 是否可以更改此: …对三元运算符? 问题答案: 好吧,中的行为就像这样…… …另一种看待它的方式… 你的问题有点含糊,我们必须在这里假设。 如果(且仅当)声明了一个返回值(,等。)-现在看来似乎没有做到这一点通过你的代码-那么你可以做到这一点… 如果callFunction(…)不返回值,那么你将无法使用三元运算符!就那么简单。你将使用不需要的东西。 请发布更多代码以清除所有问题 尽管

  • 问题内容: 是否可以在Python中一行执行此操作? 我已经尝试过三元运算符: 但是我的IDE(MyEclipse)不喜欢它,没有一个。 问题答案: 是的,您可以这样做: 如果为假,则短路将开始,并且右侧将不被评估。如果为true,则将评估右侧并添加元素。 我只是指出,执行上述操作是完全非Python的,无论如何,最好编写此代码: 示范:

  • 问题内容: 有人可以解释为什么这样的代码吗? 产生以下编译器错误: 不兼容的条件操作数类型ArrayList和HashSet 由于我不明白的原因,以下内容解决了该问题 我正在使用Java 1.4。 问题答案: 这是1.4 中的 错误 ,并已根据bugreport 5080917 进行了修复。 评估 这是一个错误。 xxxxx @ xxxxx 2004-07-30

  • 问题内容: 如何将字符串转换成运算符plus?谢谢! 问题答案: 使用查找表: