Why doesn't inheritance work the way I think i

2019-06-16 21:24发布

I'm having some inheritance issues as I've got a group of inter-related abstract classes that need to all be overridden together to create a client implementation. Ideally I would like to do something like the following:

abstract class Animal
{
  public Leg GetLeg() {...}
}

abstract class Leg { }

class Dog : Animal
{
  public override DogLeg Leg() {...}
}

class DogLeg : Leg { }

This would allow anyone using the Dog class to automatically get DogLegs and anyone using the Animal class to get Legs. The problem is that the overridden function has to have the same type as the base class so this will not compile. I don't see why it shouldn't though, since DogLeg is implicitly castable to Leg. I know there are plenty of ways around this, but I'm more curious why this isn't possible/implemented in C#.

EDIT: I modified this somewhat, since I'm actually using properties instead of functions in my code.

EDIT: I changed it back to functions, because the answer only applies to that situation (covariance on the value parameter of a property's set function shouldn't work). Sorry for the fluctuations! I realize it makes a lot of the answers seem irrelevant.

17条回答
叼着烟拽天下
2楼-- · 2019-06-16 22:20

Dog should return a Leg not a DogLeg as the return type. The actual class may be a DogLeg, but the point is to decouple so the user of Dog doesn't have to know about DogLegs, they only need to know about Legs.

Change:

class Dog : Animal
{
  public override DogLeg GetLeg() {...}
}

to:

class Dog : Animal
{
  public override Leg GetLeg() {...}
}

Don't Do this:

 if(a instanceof Dog){
       DogLeg dl = (DogLeg)a.GetLeg();

it defeats the purpose of programing to the abstract type.

The reason to hide DogLeg is because the GetLeg function in the abstract class returns an Abstract Leg. If you are overriding the GetLeg you must return a Leg. Thats the point of having a method in an abstract class. To propagate that method to it's childern. If you want the users of the Dog to know about DogLegs make a method called GetDogLeg and return a DogLeg.

If you COULD do as the question asker wants to, then every user of Animal would need to know about ALL animals.

查看更多
家丑人穷心不美
3楼-- · 2019-06-16 22:20

Not that it is much use, but it is maybe interesting to note the Java does support covariant returns, and so this would work exactly how you hoped. Except obviously that Java doesn't have properties ;)

查看更多
我只想做你的唯一
4楼-- · 2019-06-16 22:21

Clearly, you'll need a cast if you're operating on a broken DogLeg.

查看更多
等我变得足够好
5楼-- · 2019-06-16 22:23

@Luke

I think your perhaps misunderstanding inheritance. Dog.GetLeg() will return a DogLeg object.

public class Dog{
    public Leg GetLeg(){
         DogLeg dl = new DogLeg(super.GetLeg());
         //set dogleg specific properties
    }
}


    Animal a = getDog();
    Leg l = a.GetLeg();
    l.kick();

the actual method called will be Dog.GetLeg(); and DogLeg.Kick() (I'm assuming a method Leg.kick() exists) there for, the declared return type being DogLeg is unneccessary, because that is what returned, even if the return type for Dog.GetLeg() is Leg.

查看更多
时光不老,我们不散
6楼-- · 2019-06-16 22:25

You can achieve what you want by using a generic with an appropriate constraint, like the following:

abstract class Animal<LegType> where LegType : Leg
{
    public abstract LegType GetLeg();
}

abstract class Leg { }

class Dog : Animal<DogLeg>
{
    public override DogLeg GetLeg()
    {
        return new DogLeg();
    }
}

class DogLeg : Leg { }
查看更多
登录 后发表回答