为什么显式允许具有2个或更多(非默认)参数的默认构造函数和构造函数?

Ash*_*ppa 32 c++ explicit-constructor

我理解具有一个(非默认)参数的构造函数就像隐式转换器,它从该参数类型转换为类类型.但是,explicit可用于限定任何构造函数,没有参数的构造函数(默认构造函数)或具有2个或更多(非默认)参数的构造函数.

为什么明确允许这些构造函数?有什么例子可以防止某种隐式转换吗?

Joh*_*itb 37

一个原因当然是因为它没有伤害.

需要的一个原因是,如果您有第一个参数的默认参数.构造函数成为默认构造函数,但仍可用作转换构造函数

struct A {
  explicit A(int = 0); // added it to a default constructor
};
Run Code Online (Sandbox Code Playgroud)

C++ 0x实际上将它用于多参数构造函数.在C++ 0x中,初始化列表可用于初始化类对象.理念是

  • 如果使用= { ... },则初始化对象与一种"化合物值"在概念上表示对象的抽象值,并且要已经转换到的类型.

  • 如果使用{ ... }初始值设定项,则直接调用对象的构造函数,而不一定要指定转换.

考虑这个例子

struct String {
    // this is a non-converting constructor
    explicit String(int initialLength, int capacity);
};

struct Address {
    // converting constructor
    Address(string name, string street, string city);
};

String s = { 10, 15 }; // error!
String s1{10, 15}; // fine

Address a = { "litb", "nerdsway", "frankfurt" }; // fine
Run Code Online (Sandbox Code Playgroud)

通过这种方式,C++ 0x显示C++ 03的决定,允许在其他构造函数上显式,根本不是一个坏主意.


Adr*_*scu 7

这可能只是一个方便; 没有理由解散 -ALLOW,所以为什么过不去代码生成器,等等?如果您选中了,则代码生成例程必须有一个额外的步骤来验证生成的构造函数有多少参数.

根据各种 来源,当应用于无法使用一个参数调用的构造函数时,它根本没有任何影响.


Che*_*Alf 7

也许是为了支持维护.通过explicit在多参数构造函数上使用,可以避免在向参数添加默认值时无意中引入隐式转换.虽然我不相信; 相反,我认为只是在C++中允许许多事情只是为了不使语言定义比现在更复杂.

也许最臭名昭着的案例是返回对非static局部变量的引用.它需要额外的复杂规则来排除所有"无意义"的事情,而不会影响其他任何事情.所以它只是被允许,如果你使用那个引用就会产生UB .

或者对于构造函数,只要它们的签名不同,就可以定义任意数量的默认构造函数,但是如果有多个默认构造函数,则默认情况下调用它们是相当困难的.:-)

或许更好的问题是,为什么explicit转换运算符也不允许?

好吧,它将在C++ 0x中.所以没有充分理由不这样做.不允许explicit转换运营商的实际原因可能是疏忽,或者explicit首先要采用的斗争,或委员会时间的简单优先排序,或其他什么.

干杯&hth.,


ArB*_*rBR 6

根据高完整性C++编码标准, 您应该将所有sinlge参数构造函数声明为 显式, 以避免在类型转换中偶然使用.在它是一个多参数构造函数的情况下,假设你有一个接受多个参数的构造函数,每个参数都有一个默认值,在某种默认构造函数和转换构造函数中转换构造函数:

class C { 
    public: 
    C( const C& );   // ok copy 
    constructor C(); // ok default constructor 
    C( int, int ); // ok more than one non-default argument 

    explicit C( int ); // prefer 
    C( double ); // avoid 
    C( float f, int i=0 ); // avoid, implicit conversion constructor 
    C( int i=0, float f=0.0 ); // avoid, default constructor, but 
                               // also a conversion constructor 
}; 
void bar( C const & ); 
void foo() 
{ 
    bar( 10 );  // compile error must be 'bar( C( 10 ) )' 
    bar( 0.0 ); // implicit conversion to C 
}
Run Code Online (Sandbox Code Playgroud)