C++:显式构造函数被派生类隐式调用

3
为什么将构造函数设置为explicit后,派生类仍然可以隐式调用它?
class A{
public:
    explicit A(){}
};

class B : public A{
public:
    B(){ //Constructor A() is called implicitly

        //...
    }
}

在我的程序中,我遇到了一个情况,在那种情况下,我更希望有编译器错误,这会节省我很多时间去查找错误。目前,我已经改变了 A 的默认构造函数来接受一个虚拟的 "int" 参数来实现这一点,但是应该使用 "explicit" 关键字才能解决吗?

g++-4.8 编译上述代码没有任何错误或警告。


6
它并不是为了避免被派生类调用,而是为了在实例化该类型的对象时避免隐式转换。 - Marco A.
要创建B,必须调用A的构造函数。如果您没有指定自定义构造函数,则使用默认构造函数是有意义的。 - yizzlez
在什么情况下,隐式调用默认构造函数与显式调用有所不同? - juanchopanza
问题在于当有人扩展我定义了两个构造函数(一个没有参数,一个有一个参数)的类时容易出错。简而言之,我需要强制那个人通过派生类构造函数调用带有一个参数的基类构造函数。因此,我需要防止从具有一个参数的派生类构造函数隐式使用没有参数的构造函数。 - igagis
2个回答

8
您对于 explicit 关键字的假设是错误的。 explicit 关键字并不是为了防止派生类中调用构造函数,而是为了防止隐式转换。就像这个示例中的一样:https://dev59.com/fXVD5IYBdhLWcg3wAWkO#121163 以下是相关内容的摘要:
class Foo
{
public:
  // single parameter constructor, can be used as an implicit conversion
  Foo (int foo) : m_foo (foo) 
  {
  }

  int GetFoo () { return m_foo; }

private:
  int m_foo;
};

由于最多只能进行一次隐式转换以解决模糊性,如果您有一个像这样的函数

void DoBar (Foo foo)
{
  int i = foo.GetFoo();
}

以下是合法的:
int main ()
{
  DoBar (42); // Implicit conversion
}

这正是explicit关键字发挥作用的地方:禁止上述情况。

为了解决你的问题,防止你的类被用作基类,只需在构造函数中标记为final(如果你使用的是C++11)(http://en.wikipedia.org/wiki/C++11#Explicit_overrides_and_final)。


所以,标准似乎直接说明了explicit关键字只是为了防止隐式自动转换... - igagis

1

explicit关键字通常与只有一个参数的构造函数一起使用。它可以防止从参数类型到类类型的隐式构造对象。

下面的示例将编译,但通常不是您想要的:

#include <iostream>
using namespace std;

struct Test
{
    Test(int t) {}
};

void test_fun(Test t) {}

int main() {
    test_fun(1); //implicit conversion
    return 0;
}

使用explicit关键字,这个例子将无法编译:

#include <iostream>
using namespace std;

struct Test
{
    explicit Test(int t) {}
};

void test_fun(Test t) {}

int main() {
    test_fun(1); //no implicit conversion, compiler error
    return 0;
}

那个我知道,但我的问题是为什么它也不会防止派生类隐式调用,因为它是显式的... - igagis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接