3

Why making a constructor explicit does not prevent it to be implicitly called by derived class?

class A{
public:
    explicit A(){}
};

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

        //...
    }
}

I had a situation in my program when I'd rather have compiler error in that case, it would save me a lot of time to find a bug. For now I changed default constructor of A to accept a dummy "int" argument to achieve that, but shouldn't "explicit" keyword work for this?

g++-4.8 compiles the code above without any errors or warnings.

igagis
  • 1,959
  • 1
  • 17
  • 27
  • 6
    it isn't meant to avoid being called by derived classes, it is meant to avoid implicit conversions when instantiating an object of that type – Marco A. Jun 17 '14 at 19:44
  • For `B` to be created, the constructor of `A` must be called. It makes sense that if you don't specify a custom constructor, the default one is used. – yizzlez Jun 17 '14 at 19:45
  • What situation do you have where it would make a difference to call the default constructor implicitly rather than explicitly? – juanchopanza Jun 17 '14 at 19:59
  • Problem is error proneness when somebody extends my class which defines 2 constructors, without arguments and with 1 argument. In short, I need to force that somebody to call base class constructor with one argument by derived class constructor with one argument. So, I need to prevent implicit use of constructor without arguments from derived class constructor with one argument. – igagis Jun 19 '14 at 14:12

2 Answers2

8

Your assumption is wrong on the explicit keyword.

The explicit keyword isn't meant to prevent the constructor from being called from a derived class but rather to prevent implicit conversions like the one in the sample here: https://stackoverflow.com/a/121163/1938163

I'm summarizing the relevant parts here:

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;
};

Since at most one implicit conversion can be done to resolve ambiguities, if you have a function like

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

the following is legit:

int main ()
{
  DoBar (42); // Implicit conversion
}

And that's exactly where the explicit keyword comes into play: forbids the case above.

To solve your problem, in order to prevent your class from being used as a base class, just mark the constructor with final if you're using C++11 (http://en.wikipedia.org/wiki/C++11#Explicit_overrides_and_final)

Community
  • 1
  • 1
Marco A.
  • 43,032
  • 26
  • 132
  • 246
  • So, it seems that standard directly says that explicit keyword is only to prevent implicit auto-conversion... – igagis Jun 19 '14 at 14:14
1

explicit keyword is usually used with constructors that have one parameter. It prevents implicit construction of the object from type of the parameter to type of the class.

The example below will compile, and it usually is not what you want:

#include <iostream>
using namespace std;

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

void test_fun(Test t) {}

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

With explicit keyword this example won't compile:

#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;
}
matekm
  • 5,990
  • 3
  • 26
  • 31
  • That I know, but my question is why it also does not prevent calling by derived class implicitly, since it is explicit... – igagis Jun 19 '14 at 14:08