Why can't I create an abstract constructor on an abstract C# class?

171

Solution 1

You cannot have an abstract constructor because abstract means you must override it in any non-abstract child class and you cannot override a constructor.

If you think about it, this makes sense, since you always call the constructor of the child class (with the new operator) and never the base class.

Generally speaking, the only way in C# to enforce a specific constructor signature is by using the new() generic constraint, which enforces the existence of a parameterless constructor for the type parameter.

Solution 2

Change that constructor in class A to

protected A(int a, int b)
{
    // Some initialisation code here
}

Then your subclasses will have to use it, as there is no default constructor.

They can, however, still change the actual signature of the constructor. There is no way of forcing a subclass to use a specific signature for its constructor as far as I know. I'm pretty sure constructors can't be abstract.

What exactly do you need this for? We might be able to suggest a work around for this.

Solution 3

Although you can't override constructors, and therefore can't define an abstract constructor, you can place an abstract factory method in your abstract base class. All the derived classes would need to override that.

public abstract class A 
{ 
    abstract A MakeAInstance(int a, int b); 
} 

public class B : A 
{ 
    // Must implement:
    override A MakeAInstance(int a, int b) {
        // Awesome way to create a B instance goes here
    }
} 

Solution 4

Multiple reasons:

1) Constructors are not inherited thus you cannot override them.

2) The constructor is a static member function since it dont need a specific instance to be called. Abstract implies "virtual" which means that the implementation can vary depending on how a specific instance is subclassed, which is the opposite of the intention of the meaning of the "static" keyword.

Solution 5

You cannot enforce constructor signature, as each derived class may (must!) define its own constructor(s), and they may take any parameters they like.

If you need to pass a given set of variables to an object of a derived class, define an abstract method which needs to be implemented by derived classes. If the classes do not implement the abstract method, you will get a compiler error.

Share:
171
Greg Samson
Author by

Greg Samson

Updated on July 08, 2022

Comments

  • Greg Samson
    Greg Samson almost 2 years

    I am trying to run lint and tests separately with tox-travis, but I cannot seem to get the right combo.

    Here are the two base files:

    tox.ini

    [tox]
    envlist = py27, py34, py35, py36, lint
    
    [travis]
    python =
        3.6: py36
        3.5: py35
        3.4: py34
        2.7: py27   
    
    [travis:env]
    LINT = 
         yes: py36, lint
    
    [testenv:lint]
    ....
    
    [testenv]
    ...
    commands = 
        pip install -U pip
        py.test --basetemp={envtmpdir}
    

    travis.yml

    language: python
    python:
      - 3.6, lint
      - 3.5
      - 3.4
      - 2.7
    matrix:
      include:
        - python: 3.6
          env:
            - LINT=yes
    install: pip install -U tox-travis
    script: tox
    
    • When python={3.6,3.5,3.4,2.7} and LINT is not set only tests are run. (correct).
    • When python=3.6 and LINT=yes it runs NEITHER lint or tests. (incorrect)

    Setting

    LINT = 
         yes: lint
    
    • When python={3.6,3.5,3.4,2.7} and LINT is not set only tests are run. (correct).
    • When python=3.6 and LINT=yes it runs neither tests or lint. (incorrect)

    Setting: 3.6: py36,lint and yes: lint runs lint whenever python=3.6 regardless of LINT value.


    What am I doing wrong here?

  • Thorsten
    Thorsten about 15 years
    I think they can add other constructors (with a different signature), but they'll be forced to implement at least the signature as defined in the protected "constructor".
  • Anthony D
    Anthony D about 15 years
    This answer does not accomplish what I want.
  • DkAngelito
    DkAngelito over 12 years
    but in this case you must first create an instance of class B to be able to call the method MakeAInstance and get a new one
  • John Saunders
    John Saunders over 12 years
    Yes, exactly, or one must be passed to your code that then calls instance.MakeAInstance(1,2)
  • Tilak
    Tilak about 12 years
    calling overrides in constructor is not recommended.
  • Matthew
    Matthew about 12 years
    I disagree with your statement of a constructor is a static member, it does need an instance to be called (since you can access instance methods, fields, etc.). The new keyword instanciates the object, and then the constructor gets called, the constructor itself doesn't "construct" the object.
  • CptRobby
    CptRobby over 10 years
    Actually the .aspx and .aspx.cs both define the same class. So the .aspx page is not "inheriting" the class in the .aspx.cs code, (despite the fact that it is referred to in the <%Page%> directive as "Inherits") but is actually defining a partial to that same class.
  • Syroot
    Syroot about 10 years
    Does C# 6 change this rule with the primary constructors?
  • Jeppe Stig Nielsen
    Jeppe Stig Nielsen about 9 years
    The constructor is an instance method (i.e. a non-static method), as seen from a CIL perspective. It might look like: .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { ... } So its name is .ctor, it is instance not static, and its return type is void. (Its accessibility maybe be different from public, and its parameter list may contain some args.)
  • jeromej
    jeromej over 5 years
    Can you give an example with new()? Isn't that the dangerous keyword that hides inherited member or it's something else?
  • Sinjai
    Sinjai over 2 years
    Years later: jeromej is referring to the keyword new, which is used to hide (NOT override, though the goal and outcome are simiilar) a member of the base class which is not virtual or abstract. That is different than the new() constraint.