有没有一种方法可以在函数中返回抽象类的不同变体而又不会将信息丢失给切片?

比如说,我有一个抽象类“狗”,而狗有WildDog,DomesticDog,Puppy。

是否可以创建一个接受这些函数之一的函数并在不分割信息的情况下返回它们?

例:

// Returns the type of dog you currently have
Dog getCurrentDog() {
    return this.dog;
}

void setDog(Dog dog) {
    this.dog = dog;
}


是否可以将WildDog或PuppyDog传递给setDog并将所有信息保留在相应的类中。举一个例子,PuppyDog具有其他狗所没有的DrinkMilk()函数,但是我仍然希望能够访问它。

如果可能的话,Java等效物是什么?

我现在正在考虑的解决方案是为Dog的每个实例都具有一个getDog(),以返回该狗的特定实例,无论是Puppy还是WildDog。这样,我可以专门访问每个类中的代码。

最佳答案

为了避免切片,您需要将指针或引用传递给Dog。请参见object slicing

std::shared_ptr<Dog> getCurrentDog()
{
    return dog;
}


为了在PuppyDog等中使用函数,您需要在抽象的virtual类或Dog中将它们声明为dynamic_castdynamic_cast通常表示设计不良,但实际上,所有狗都可以喝牛奶,因此在您的Dog类中声明它们是有道理的:

class Dog
{
    public:
        virtual void drinkMilk(); // not pure virtual: all dogs can drink milk
};

class PuppyDog : public Dog
{
    public:
       // puppies drink less milk, and do it more messily
       void drinkMilk() override;
};


现在您可以拥有以下内容:

 // getCurrentDog is a PuppyDog
 std::shared_ptr<Dog> myDog = someOwner.getCurrentDog();
 myDog->drinkMilk();


有很多实例可以使用:play()rollOver()fetch(),以及所有狗可以做的所有其他事情;但是,请说您具有并非所有狗都可以执行的功能,只有PuppyDog可以。您仍然可以在基类中创建一个函数,并可以将其声明为纯虚函数,也可以将dynamic_cast更改为PuppyDog

// This if will only succeed if getCurrentDog is a PuppyDog (or something inherited PuppyDog) and if getCurrentDog != nullptr
if (std::shared_ptr<PuppyDog> myPuppy = std::dynamic_pointer_cast<PuppyDog>(someOwner.getCurrentDog()))
{
     // do something only a puppy would:
     myPuppy->beExtremelyCute();
}


正如@PaulMcKenzie指出的那样,它经常是设计缺陷,并且偏离了面向对象的编程(因为您最终会得到“如果它是WildDog,请执行此操作;如果它是PuppyDog,请执行此操作”等)

关于java - 返回抽象类的实例而不进行切片,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35304747/

10-11 01:33