Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I pass arguments to a base constructor from a derived class's default constructor?

Suppose I have an abstract base class Deck:

public abstract class Deck
{
   public List<Card> cards;

   public Deck(string[] values, string[] suits)
   {...}

   ...
}

and a derived class EuchreDeck:

public class EuchreDeck : Deck
{
   string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
   string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };

   public EuchreDeck() : base(values, suits) // Error.
   {}

   ...
}

I want the ability to instantiate EuchreDeck and have the two string arrays passed to the base class, i.e. var gameDeck = new EuchreDeck();.

Currently I'm getting the error: "An object reference is required for the non-static field, method, or property EuchreDeck.values."

Is this possible, or will calling the derived default constructor always call the base default constructor?

like image 982
Zach Avatar asked Sep 10 '13 12:09

Zach


People also ask

Can we pass parameters to base class constructor through derived?

show();// displays 3 4 return 0; } A derived class' constructor is free to make use of any and all parameters that it is declared as taking, even if one or more are passed along to a base class. Put differently, passing an argument along to a base class does not preclude its use by the derived class as well.

Can we call base class constructor from derived class?

We have to call constructor from another constructor. It is also known as constructor chaining. When we have to call same class constructor from another constructor then we use this keyword. In addition, when we have to call base class constructor from derived class then we use base keyword.

Can the constructor of a derived class have more parameters than the constructor of its base class?

Sure. All objects inherit from object which has no constructor parameters, so the fact that some objects have constructors to with more than one parameter proves it can be done.

Can a constructor be inherited by a derived class from the base class in Java?

Constructors are not members, so they are not inherited by subclasses, but the constructor of the superclass can be invoked from the subclass.


2 Answers

Yes, you can do this if you make the arrays static:

public class EuchreDeck : Deck
{
   private static readonly string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
   private static readonly string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };

   public EuchreDeck() : base(values, suits)
   {

   }
}

The reason why you can't use it as you had with instance-level members is because it's not legal to do so. This comes from the C# specification 10.10.1 Constructor Initializers where it states:

An instance constructor initializer cannot access the instance being created. Therefore it is a compile-time error to reference this in an argument expression of the constructor initializer, as is it a compile-time error for an argument expression to reference any instance member through a simple-name.

By switching the arrays to be static, they are no longer accessed via the instance but rather by the EuchreDeck type.


That said, I might suggest you take a slight tweak on the design. Maybe use a factory to create these specialized decks for you rather than their constructors.

As an example, maybe refactor something like this:

Change your base Deck to just take the set of cards:

public abstract class Deck
{
    public List<Card> Cards;
    protected Deck(IEnumerable<Card> cards)
    {
        this.Cards = new List<Card>(cards);
    }
}

Then have the factory setup like this:

public class EuchreDeck : Deck
{
    private EuchreDeck(IEnumerable<Card> cards) : base(cards)
    {

    }

    public class Factory : DeckFactory
    { 
        private static readonly string[] Values = new string[] { "9", "10", "J", "Q", "K", "A" };
        private static readonly string[] Suits = new string[] { "clubs", "spades", "hearts", "diamonds" };

        public static EuchreDeck Create()
        {
            var cards = CreateCards(Values, Suits);
            return new EuchreDeck(cards);
        }
    }
}

Instantiation/usage as:

EuchreDeck.Factory.Create();

You could play around with the factory usage. I just nested it in the class so you couldn't create a EuchreDeck with an invalid set of cards. Your DeckFactory base would have your conversion method (which looks like you currently have in your Deck constructor)

Beyond that, I'm not sure if you have a specific need for a EuchreDeck; I'm assuming you have other methods associated with it? If not, you could probably ditch the class altogether and just let the factory create a Deck with the needed cards.

like image 117
Chris Sinclair Avatar answered Sep 28 '22 07:09

Chris Sinclair


I think the problem is that the values and suits should be declared static.

static string[] values = new string[] { "9", "10", "J", "Q", "K", "A" };
static string[] suits = new string[] { "clubs", "spades", "hearts", "diamonds" };

That way, they will be available at when instantiating the new class.

like image 43
elnigno Avatar answered Sep 28 '22 07:09

elnigno