简体   繁体   中英

Using instantiated class members as variables in abstract class methods

I'm trying to figure out how to make a method in a base abstract class capable of using member values of instantiated objects derived from the class. For example, let's say I have a class called Vehicle that inherits an interface called IVehicle ;

public abstract class Vehicle : IVehicle
{
    public int Wheels = 4;

    public int CountWheels()
    {
        return Wheels;
    }
}

Let's say I then had another class called Motorcycle that inherited Vehicle as such;

public class Motorcycle : Vehicle, IVehicle
{
    public int Wheels = 2;
}

If I make a new Motorcycle called newMotorcycle and I call newMotorcycle.CountWheels() , I get 4 instead of 2. I'm assuming this is an issue with my Wheels definition in the Motorcycle class, but I've tried just about everything I can think of to get this to work and it always seems to want to ignore child class definitions. I know that I could make the CountWheels() method abstract and define it in the Motorcycle class, but I'm trying to keep the base Vehicle class as generic as possible so I can implement a ton of other child classes without having to redefine the same method over and over.

My first question; is what I'm trying to do even possible? If so, what part of my member definition needs to change for this to work the way I'm intending for it to?

I promise I scoured the internet before I posted this here and I couldn't find enough information to help myself...

You will notice that there is a warning in the code you posted:

Motorcycle.Wheels hides inherited member Vehicle.Wheels...

Hence your problem, Vehicle has no idea that a derived class has hidden one of its members (hence why hiding is a bad idea).

Since you can't have virtual fields, you should change it to a virtual (or in this case, abstract so everyone has to define it) property :

public abstract class Vehicle : IVehicle
{
    public abstract int Wheels {get;}

    public int CountWheels()
    {
        return Wheels;
    }
}

public class Motorcycle : Vehicle, IVehicle
{
    public int Wheels => 2;
}

Now every derived class will have to have a Wheels property that the base class can use.

You need to make the Wheels member virtual and override it, otherwise you're just "hiding" the base member. You'll also need to change it to a property in order to make it virtual :

public abstract class Vehicle 
{
    public virtual int Wheels { get { return 4; } }

    public int CountWheels()
    {
        return Wheels;
    }
}

public class Motorcycle : Vehicle
{
    public override int Wheels { get { return 2; } }
}

Look up virtual properties and methods ( https://msdn.microsoft.com/en-us/library/9fkccyh4.aspx )

You need Wheels to be public virtual int Wheels {get; set;} public virtual int Wheels {get; set;} in base and public override int Wheels {get; set;} public override int Wheels {get; set;} in derived

Then you can initialize the value as you need in each class.

Here's another option. Rather than defining Wheels as a virtual property on Vehicle , and overriding that property on Motorcycle , you can define Wheels as an ordinary property and then set it in the constructor for Motorcycle :

public abstract class Vehicle : IVehicle
{
    public int Wheels { get; protected set; }

    public Vehicle()
    {
        Wheels = 4;
    }

    public int CountWheels()
    {
        return Wheels;
    }
}

public class Motorcycle : Vehicle, IVehicle
{
    public Motorcycle()
    {
        Wheels = 2;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM