c++ 所有派生类的所有函数都有一个默认实现好吗

ou6hu8tu  于 2023-05-30  发布在  其他
关注(0)|答案(3)|浏览(101)

我试图写一个代码模型,这样有一个基类和两个不同的类继承它,例如:-动物类与狗和猫类继承

Animal* a = new Dog();

playWith(a);

现在playWith函数将animal *作为参数,并且应该与dog示例或cat示例一起工作,并且将调用可能对它们专用的各种函数,例如dog的fetch或cat的climb
dog和cat类都有一些相同的函数,这些函数将在animal类中声明和定义,但也有一些函数只对一个类专用
我通过声明animal类中的所有独占函数,并使用一个virtual关键字和一个只抛出错误的实现,使代码能够正常工作
然后我在派生类中定义了实际的实现
现在我的问题是,这是一个好的方法来定义函数,如果不是你能建议一些替代
更新:
举个简单的例子

class Animal {
public:
    void walk(); // all classes are able to call this function and it is inherited from here
    
    virtual void fetch(); // they have an error message such as not implemented
    virtual void climb();
}

class Dog : public Animal {
public    
    void fetch();
}

class Cat : public Animal {
public:
    void climb();
}

class Human{ // complex class with other functions also
    void playWith(Animal* a){ // Please note that this might be part of something else such as another class 
         ...
    }
}

int main(){
    Animal a = new Dog();
    Human h = new Human();
    h->playWith(a);
}

这目前适用于调用的派生类的正确函数
更新2:
目前,我不能将它们声明为纯虚函数,因为Cat类不知道如何获取,Dog类不知道如何爬,如果我将它们声明为纯虚函数,则需要定义它们。

pes8fvy9

pes8fvy91#

您正在寻找的替代方法是纯虚函数

virtual void playWith(animal *) = 0;

编译器将强制子类创建一个实现,这比运行时错误要好得多。现在,还有其他部分看起来风格不正确。如果playWithAnimal类的一个方法(建议类以大写字母开头),那么就没有参数。如果它应该有一个参数,this使用传入的animal,那么我将通过引用传递:playWith(Animal& a)
也不鼓励使用原始指针。另一个动物可以在堆栈上创建吗?如果没有,您应该考虑std::unique_ptrstd::shared_ptr

unftdfkk

unftdfkk2#

C++中多态性的一个方面是将你的函数声明为virtual,并根据需要将你的每个派生类声明为override。一旦示例化了Dog对象,就调用它的重写方法,这样可以防止交叉调用其他派生类的方法。

fkvaft9z

fkvaft9z3#

不要将独占函数作为虚函数放在基类animal中。那是一个相当糟糕的设计。
相反,创建一个新的全局函数,它接受一个dog或一个cat示例,并使用 downcastinganimal*指针转换为正确的类型:

dogOnlyFunction(static_cast<dog*>(a));

虽然设计,甚至是需求及其分析,似乎一开始就有缺陷,但您可以使用 dynamic downcasting来解决它,这是在运行时检查的:

void playWith(animal* a)
{
    a->walk();  // Common function

    if (auto d = dynamic_cast<dog*>(a); d != nullptr)
    {
        d->fetch();  // Dog specific function
    }
    else if (auto c = dynamic_cast<cat*>(a); c != nullptr)
    {
        c->climb();  // Cat specific function
    }
}

从这个例子中可以看出,当添加更多类型时,这不能很好地扩展。因此,一个更好的解决方案可能是创建一个虚 * 成员 * 函数playWidth,它在子类中被重写并调用它们的特定函数:

struct animal
{
    virtual void playWidth() = 0;
    virtual void walk() = 0;
};

struct dog : public animal
{
    void playWidth() override
    {
        walk();    // Call the common function
        fetch();   // Call the dog specific function
    }

    void walk() override
    {
        // TODO: Walk
    }

    void fetch()
    {
        // TODO: Fetch
    }
};

struct cat : public animal
{
    void playWidth() override
    {
        walk();    // Call the common function
        climb();   // Call the cat specific function
    }

    void walk() override
    {
        // TODO: Walk
    }

    void climb()
    {
        // TODO: Climb
    }
};

在上面的例子中,我将公共walk函数作为一个纯虚函数留在基类中,这样所有子类都需要覆盖它。如果不是所有的子类都应该有walk函数,那么它可以像fetchclimb一样是特定于类的。
现在不使用全局void playWith(Animal*)函数,只需调用a->playWidth();

相关问题