参数传递期间的类类型转换:为什么不调用类型转换功能

时间:2012-03-12 01:37:00

标签: c++

这是我的代码:

  1     #include <cstdio>
  2 
  3     struct Foo;
  4 
  5     struct Bar {
  6         Foo *foo;
  7         Bar(const Foo& fo) {
  8             printf("In Bar copy_contr\n");
  9         }
 10 
 11         Bar&  operator=(Foo& fo) {
 12             printf("In Bar assignment\n");
 13             this->foo = &fo;
 14         }
 15     };
 16 
 17     struct Foo {
 18         Bar *bar;
 19         Foo() {
 20             printf("In default\n");
 21         }
 22 
 23         Foo(const Bar& b) {
 24             printf("In Foo copy constructor\n");
 25         }
 26 
 27         operator Bar() {
 28             printf("In typecast from Foo to Bar\n");
 29             return *(this->bar);
 30         }
 31 
 32     };
 33 
 34 
 35     int f(Bar b) {
 36         return 0;
 37     }
 38 
 39     int main() {
 40         Foo fo;
 41         f(fo);
 42         Bar *b = &static_cast<Bar>(fo);
 43 
 44         return 0;
 45     }

这是打印输出:

In default
In typecast from Foo to Bar
In Bar copy_contr

我对第3次打印输出感到困惑:如何调用复制构造函数,它应该是类型转换,那里有特定的static_cast。

我也有一个有趣的发现 - 如果我注释掉第27行 - 第30行,基本上会消除类型转换功能,打印输出更改为     在默认情况下     在Bar copy_contr中     在Bar copy_contr

所以看起来编译器有一些机制可以按某种顺序搜索一些转换函数,任何人都有标准的强制说明机制是什么?

我正在使用g ++ v4.1.2。

谢谢!

2 个答案:

答案 0 :(得分:2)

  

我对第3次打印输出感到困惑:如何调用复制构造函数,它应该是类型转换,那里有特定的static_cast。

表达式 static_cast&lt; T&gt;(v)的结果是将表达式v转换为T类型的结果。

如果声明 T t(e),则可以使用 static_cast&lt; T&gt;(e)形式的static_cast将表达式e显式转换为类型T.对于一些发明的临时变量来说,这是一个良好的形式。

这种显式转换的效果与执行声明和初始化,然后使用临时变量作为转换结果相同。

由此可以清楚地说明为什么在这种情况下调用转换构造函数。

  

我也有一个有趣的发现 - 如果我注释掉第27行 - 第30行,基本上会消除类型转换功能,打印输出更改为默认情况下在栏中copy_contr在栏中copy_contr

您在问为什么选择转换函数 Foo :: operator Bar (如果可用)将参数fo从Foo转换为Bar而不是转换构造函数 Bar :: Bar( const Foo&amp;) ....

  

所以看起来编译器有一些机制可以按某种顺序搜索一些转换函数,任何人都有标准的强制说明机制是什么?

用户定义的转换仅在明确无误的情况下应用。但请注意以下特定情况:

  1. Foo fo 是非常规的(即不是“const Foo fo;”)
  2. Foo :: operator Bar()是非const的(即不是“Foo :: operator Bar()const”)
  3. Bar :: Bar(const Foo&amp;)是const(即不是“Bar :: Bar(Foo&amp;)”)
  4. 因此选择的转换是 Foo :: operator Bar(),原因与:

    class X
    {
        void f();
        void f() const;
    };
    
    X x;
    x.f();
    

    上面选择了f的非const版本。 Foo fo是非const的,因此选择了非const版本。

    如果转换函数是const或者转换构造函数采用了非const引用,那么就会出现歧义并且不会编译。

    如果转换函数是const并且转换构造函数采用了非const引用,它将选择转换构造函数而不是转换函数。

答案 1 :(得分:0)

您认为“演员”和“转换”之间的区别是什么?演员要求将一个值转换为另一个值。类类型之间的转换是通过构造进行的。

也许你正试图将Foo对象重新解释为Bar?这需要不同的语法。

您在代码中使用了错误的术语。您称为“复制构造函数”的两个构造函数根本不是复制构造函数。它们是转换构造函数。它们允许从Foo构建Bar,反之亦然。

复制构造函数允许从类X的现有实例构造类X的实例。

如果您将printf更改为“In ...转换构造函数”,则会更有意义。