57

I have a base class Character which has several classes deriving from it. The base class has various fields and methods.

All of my derived classes use the same base class constructor, but if I don't redefine the constructor in my derived classes I get the error:

Error: Class "child class" doesn't contain a constructor which takes this number of arguments

I don't want to redefine the constructor in every derived class because if the constructor changes, I have to change it in every single class which, forgive any misunderstanding, goes against the idea of only writing code once?

Mike G
  • 4,232
  • 9
  • 40
  • 66
Tom
  • 2,973
  • 3
  • 28
  • 32
  • 1
    What type of work are you doing in your constructor? Generally speaking, no work other than instantianing members should be done in a constructor. – alexn Nov 28 '10 at 13:16
  • Yes just instantiating members. The base class contains 5 fields which all derived classes use, so I'm just passing these as constructor arguments and setting the base class fields. – Tom Nov 28 '10 at 13:18
  • Kinda related but NOT a duplicate: http://stackoverflow.com/q/12051/492 – CAD bloke Nov 08 '13 at 09:18

5 Answers5

88

You can use the following syntax to call the base class constructor from the classes that derive from it:

public DerivedClass() : base() {
    // Do additional work here otherwise you can leave it empty
}

This will call the base constructor first, then it will perform any additional statements, if any, in this derived constructor.

Note that if the base constructor takes arguments you can do this:

public DerivedClass(int parameter1, string parameter2) 
    : base(parameter1, parameter2) {
    // DerivedClass parameter types have to match base class types
    // Do additional work here otherwise you can leave it empty
}

You can find more information about constructors in the following page:

https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/using-constructors

In a derived class, if a base-class constructor is not called explicitly by using the base keyword, the default constructor, if there is one, is called implicitly.

Colin
  • 1,987
  • 3
  • 17
  • 21
Waleed Al-Balooshi
  • 6,318
  • 23
  • 21
  • @user491704 glad to be of service – Waleed Al-Balooshi Nov 28 '10 at 13:22
  • 2
    public DerivedClass() : base() {}, redundant base constructor call – macio.Jun Jan 13 '15 at 19:10
  • 5
    To make @macio.Jun's comment more explicit: If a non-static constructor overload (in a `class`) contains neither `: base(...)` nor `:this (...)`, then a call to the zero-parameter base class constructor is implied. So if no chaining is mentioned explicitly, that is the same as writing `: base()`. Also, if no non-static constructors are written for a non-static `class`, the compiler will generate an empty zero-parameter constructor which chains `: base()`. – Jeppe Stig Nielsen Jul 28 '15 at 11:07
57

You do have to redeclare constructors, because they're effectively not inherited. It makes sense if you think of constructors as being a bit like static methods in some respects.

In particular, you wouldn't want all constructors to be automatically inherited - after all, that would mean that every class would have a parameterless constructor, as object itself does.

If you just want to call the base class constructor though, you don't need to write any code in the body of the constructor - just pass the arguments up to the base class as per Waleed's post.

If your base class starts requiring more information, it's natural that you should have to change all derived classes - and indeed anything calling the constructors of those classes - because they have to provide the information. I know it can seem like a pain, but it's just a natural consequence of what constructors do.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I don't get this paradigm at all. At the end of the day a constructor is just a method like any other. It just gets called to "setup" a class. If the base setup method does all the setup needed, why do derived classes need to care? How is it different than a regular method? Because of this, I have to update many derived classes just to add base class functionality. It's a time waster that serves no upside and is even ideologically inconsistent. – Slight Nov 22 '22 at 05:22
  • 1
    @Slight: It's only "ideologically inconsistent" if you consider it to be "a method like any other", which I certainly don't. As for "serves no upside" - does that mean you'd be happy for *every single class* to have a parameterless constructor, just because `Object` does? Say goodbye to any validation of the genuinely required parameters for every class. Constructors are *not* the same as regular methods - they're *only* used when creating objects, which is effectively before inheritance becomes relevant to callers. – Jon Skeet Nov 22 '22 at 07:10
  • 1
    @Slight: It might be useful to be able to explicitly declare that you want to inherit all the constructors from the base class, but I certainly wouldn't want to change the default behavior. – Jon Skeet Nov 22 '22 at 07:10
7

I had the same problem, and I solved it by replacing my constructor with a factory method like this:

A is the parent class.

public static T getChild<T>(int number) where T:A, new()
{
    T child = new T();
    T._number = number;
    return child;

}

You can create a Child class with

Child b = A.getChild<Child>(2);

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
jasdefer
  • 757
  • 12
  • 24
  • Why is this not an answer to this question? It replaces an empty constructor `public Child(int number) : base(number){}` in every child class. – jasdefer Nov 30 '14 at 11:26
  • 1
    Before @Ben edited the answer, it was like a "I'm having the same issue" post. I withdraw my first comment respectfully. – Hashem Qolami Nov 30 '14 at 11:42
  • Ah okay, you are right. It really sounded that way. Thanks for your remark. – jasdefer Nov 30 '14 at 12:16
  • 1
    @HashemQolami: You do have to thoroughly read "I have the same issue" answers to see if they also offer a solution. – Ben Voigt Nov 30 '14 at 16:18
1

A kind of alternative could be to rely on a Dependency Injection container to initialize your objects, that way the that reference to the base class (could be the call to the base constructor or another initializer method) would "externalized" to the DI container.

I don't know if it makes sense to your case or not

t3mujin
  • 1,272
  • 1
  • 9
  • 22
0

If you can use records, you would still have to repeat the name of the properties, but the syntax would be lighter and you can add more properties in the derived classes.

public abstract record GrammarElement(TokenSegment Segment)
{
  // common functions
}

public record Identifier(TokenSegment Segment, string Name):
  GrammarElement(Segment)
{
  // specific functions
}
circular
  • 171
  • 1
  • 5