8

Why is the Child pass-through constructor necessary in this code? I would think that it wouldn't be, but the compiler (gcc and VS2010) complains when I remove it. Is there an elegant workaround? It just seems pointless to have to insert this shim into child classes.

class Parent
{
public:
  Parent(int i) { }
};

class Child : public Parent
{
public:
  Child(int i) : Parent(i) { }
};

int main()
{
  Child child(4);
  return 0;
}
4
  • Yes it seems logical on such a simple example. But in more complex examples I don't want the compiler to start auto generating new constructors just because it thinks its a good idea; that may lead to all sorts of unexpected auto conversions where I don't expect them. Commented Jul 15, 2011 at 17:35
  • 1
    Bjarne Stroustrop says (link), "In C++98, we can 'lift' a set of overloaded functions from a base class into a derived class... I have said that 'Little more than a historical accident prevents using this to work for a constructor as well as for an ordinary member function.' C++0x provides that facility..." He is referring to the using statement, e.g., using Parent::Parent;, but I wonder if the lack of constructor inheritance in general is also due to arbitrary historical reasons. Commented Jul 15, 2011 at 17:46
  • 1
    Yes C++0x has provided some extra functionality. But it is not automatic you need to explicitly indicate that you want it. What you want is everything automated and that is a BAD idea because it will lead to auto type conversions that you are not expecting. I believe it was considered (this is why C++0x allows you to import them with using Parent::Parent;), but your idea was rejected (but I don't have a quote). Commented Jul 15, 2011 at 17:52
  • Related: Inheriting constructors Commented Sep 3 at 3:33

7 Answers 7

14

Because the following is perfectly valid:

class Parent
{
public:
    Parent(int i) { }
};

class Child : public Parent
{
public:
    Child() : Parent(42) { }
};

How is the compiler to guess whether you want the derived child to have a forwarded constructor? And in the case of multiple inheritance, the set of constructors from the two types may not match; when forwarding a constructor from base class A, which constructor on base class B should be called?

Technically, I suppose the language designers could have said that if the type has a single base class and in the absence of an explicit constructor, all parent constructors are forwarded. However, that creates the opposite problem: if a base class has multiple constructors including a default constructor, and the child wishes to allow only the default constructor, this must now be explicitly specified.

Sign up to request clarification or add additional context in comments.

4 Comments

I know that constructors are essentially static methods and so are different than regular methods, but I would like constructor inheritance to work the same way as far as possible. For example, if my class does not use multiple inheritance, there is no ambiguity as to which parent constructor to call because there is only one parent--the same as with regular methods.
But there are often good reasons for not wanting to forward constructors. You're proposing to add special handling for automatic constructor generation for one particular edge-case, which would complicate and already complex language (imho).
But C++ forwards other (public and protected) methods automatically. Why treat constructors different from other methods?
@plong: Because that can lead to unexpected type conversion. I like my type conversion to be explicit or at least expected.
5

If you don't specify which parent constructor should be called explicitly, the compiler will generate code which calls the default (no-argument or with all default values) constructor.

In your case, the class Parent does not have such a constructor, the compiler would not know what value to use for i.

Not specifying a constructor in class Child means that the default constructor in class Parent would be called but this does not exist.


I haven't tried it but have a look at this section of the C++0x FAQ. I have the impression what you're asking for is possible in C++0x.

1 Comment

Why would the compiler look for the default constructor if I'm passing an argument in my constructor reference? Yeah, it looks like one can "lift" a parent constructor into the child scope with C++0x.
4

It's because in C++ you have multiple inheritance. In the following example, which constructor should be inherited?

class Parent1
{
public:
  Parent1(int i) { }
};

class Parent2
{
public:
  Parent2(int i) { }
};

class Child : public Parent1, public Parent2
{
};

2 Comments

Easy - it should be the parameters of all the parent constructors, in the order they're declared. Hypothetically speaking of course. I just don't think this is the correct answer.
But since I'm not using multiple inheritance, it's obvious to which constructor I'm referring.
3

Is there an elegant workaround?

Since C++11, you can use a using declaration to inherit constructors (not including default, copy or move constructors) from a base:

class Parent
{
public:
  Parent(int i) { }
};

class Child : public Parent
{
public:
  using Parent::Parent; // inherits Parent(int)
};

int main()
{
  Child child(4);
  return 0;
}

Comments

1

Here's another case

class Parent
{
public:
  Parent(int i) {this.i = i; }
  Parent() {this.i = 0;}
private:
  int i;
};

class Child : public Parent
{
public:
  Child(int i) : { }
};

int main()
{
  Child child(4);
  return 0;
}

Given that, which Parent constructor should be called. What if Parent defines a constructor that takes in a long but not one that takes an int? Should the compiler auto-convert the int to long?

For better or worse, the language designers opted for simplicity -- the only constructor that is automatically called from a derived class is the default (no-arg or all args having defaults) constructor. Everything else needs to be explicitly called.

4 Comments

Use the normal promotion rules in C++. Why should constructors be treated any different than normal methods?
First, your desired behavior is not precisely how normal methods work. If I override foo() in a derived class, it does not automatically call the base class version of foo().
Now, it is true that if I define foo(int x) on a base class, that function is available to be called on a derived class object as is.
The reason is that construction is a fundamentally different operation than calling a function. It makes sense a derived class would need more parameters to construct itself than a base class; not so much to calculate its area, for example.
0

The compiler only autogenerates the default constructor, that is the ctr without parameters, but only if you haven't defined any constructors.

In this case, you have (in the parent), so no default is made for you, plus the child needs it so that it knows what to do with the parameter i that you are passing to it.

Comments

0

Constructors need to be called explicitly by the child constructor if you don't want to use the default one which generated by compiler, which is called default constructor (the one with no arguments). But apparently in your case you want a constructor that accepts an int, then you have to call it explicitly.

1 Comment

Yeah, I know, but I was wondering why this is so and if there is an elegant workaround. Apparently not.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.