使用继承在C++中初始化参数 我曾经读过,在C++中过度使用继承是不好的。 我有一个简单的例子,我想知道使用它初始化基类构造函数中的值是好是坏

使用继承在C++中初始化参数 我曾经读过,在C++中过度使用继承是不好的。 我有一个简单的例子,我想知道使用它初始化基类构造函数中的值是好是坏,c++,inheritance,C++,Inheritance,假设我有一个动物班: class Animal{ protected : Animal(std::string name, std::string category); std::string m_name; std::string m_category; }; 为应用程序将要使用的每种动物创建一个特定的类是否合适,例如: class Bear : public Animal{ public : Bear():Animal("Bear", "Mammal"){ } }; 当然,这意味着如果我

假设我有一个动物班:

class Animal{
protected :
Animal(std::string name, std::string category);
std::string m_name;
std::string m_category;
};
为应用程序将要使用的每种动物创建一个特定的类是否合适,例如:

class Bear : public Animal{
public :
Bear():Animal("Bear", "Mammal"){
}
};
当然,这意味着如果我有100只动物,我需要100门课,这让我觉得很尴尬。 在这个例子中,我只使用继承来初始化值,不会涉及任何特定的虚拟方法


谢谢

当您有不同的实现案例,但仍然有相同的工作基础时,继承非常有用。在你的例子中,如果所有动物之间的唯一区别是名称和类别,并且没有具体的实现,那么我个人认为这是没有用的


然而,在您的案例中可以改进的是,需要两个参数来定义相同的事物,例如熊始终是哺乳动物。在您的案例中,映射可能会解决这个问题?

当您有不同的实现案例,但仍然有相同的工作基础时,继承非常有用。在你的例子中,如果所有动物之间的唯一区别是名称和类别,并且没有具体的实现,那么我个人认为这是没有用的


然而,在您的案例中可以改进的是,需要两个参数来定义相同的事物,例如熊始终是哺乳动物。也许一张地图可以解决你的问题?

为每种动物制作一个类似乎太过分了。我以前做过一个学校作业,在那里我使用了一个动物类,我把派生类变成了捕食者和猎物。因此,将派生的类设置为特定类型的动物,如哺乳动物、鱼类等。例如,您可以使用单个动物类并将其称为动物熊。

为每种动物设置一个类似乎有些过分。我以前做过一个学校作业,在那里我使用了一个动物类,我把派生类变成了捕食者和猎物。因此,将衍生类动物定义为特定类型的动物,如哺乳动物、鱼类等。例如,您可以使用单一动物类别,并将其称为动物熊。

广义上说,选择是创建派生类还是只在一个类上有数据成员,这就变成了一个问题,即更多的类是否真的有助于您尝试在软件中建模/求解的情况

例如,一个关心车辆如何行驶的应用程序可能会有不同的汽车、轮船、飞机、直升机等类别。另一方面,一个只关心车辆存在的应用程序说它是为了跟踪企业拥有的东西,通常可能只需要一个单一类别的车辆

作为一条经验法则,问问自己,就程序的其余部分而言,派生类是否真的会以任何方式表现出不同的行为。如果是,那么派生类可能就是您想要的。如果没有,那么可能没有

在你的具体情况下,两者之间会有什么真正的区别吗

Bear bear;


如果不是,那么每种动物的一个派生类听起来太多了100个派生类通常听起来太多了,您可能想做些其他事情,这取决于您希望如何存储数据。也许是制作动物实例的列表或地图。

从广义上讲,是创建派生类,还是在一个类上只包含数据成员,这就成了一个问题,即更多的类是否真的有助于您在软件中尝试建模/解算的情况

例如,一个关心车辆如何行驶的应用程序可能会有不同的汽车、轮船、飞机、直升机等类别。另一方面,一个只关心车辆存在的应用程序说它是为了跟踪企业拥有的东西,通常可能只需要一个单一类别的车辆

作为一条经验法则,问问自己,就程序的其余部分而言,派生类是否真的会以任何方式表现出不同的行为。如果是,那么派生类可能就是您想要的。如果没有,那么可能没有

在你的具体情况下,两者之间会有什么真正的区别吗

Bear bear;


如果不是,那么每种动物的一个派生类听起来太多了100个派生类通常听起来太多了,您可能想做些其他事情,这取决于您希望如何存储数据。可能是制作动物实例的列表或地图。

通常,在基类中包含成员不是一个好的做法。相反,创建一个接口并在派生类中提供一个实现,返回以下值:

class Animal {
protected:
    virtual std::string getName() const;
    virtual std::string getCategory() const;
};

class Bear : public Animal{
public:
    virtual std::string getName() const override {
        return std::string("Bear");
    }

    virtual std::string getCategory() const override {
        return std::string("Mamal");
    }
};

通常,在基类中有成员不是一个好的做法。相反,创建一个接口并在派生类中提供一个实现,返回以下值:

class Animal {
protected:
    virtual std::string getName() const;
    virtual std::string getCategory() const;
};

class Bear : public Animal{
public:
    virtual std::string getName() const override {
        return std::string("Bear");
    }

    virtual std::string getCategory() const override {
        return std::string("Mamal");
    }
};
谢谢你的回复
呃!不会有任何区别,这更像是一个架构问题,因为我想避免使用动物构造函数创建动物,所以可能将其封装到工厂中,每个动物都有一个枚举是最好的解决方案?@DarkVapor确实,这是另一种选择。可能是一个枚举AnimalType,然后是一个函数Animal*createanimalatype,根据需要构造它们。这样,您就可以将构造的细节与使用对象的其余代码很好地分开。我确实认为这是最好的!谢谢你的回答!不会有任何区别,这更像是一个架构问题,因为我想避免使用动物构造函数创建动物,所以可能将其封装到工厂中,每个动物都有一个枚举是最好的解决方案?@DarkVapor确实,这是另一种选择。可能是一个枚举AnimalType,然后是一个函数Animal*createanimalatype,根据需要构造它们。这样,您就可以将构造的细节与使用对象的其余代码很好地分开。我确实认为这是最好的!你确定吗?那对我来说似乎很肮脏-我认为它一点也不脏,它比基类被不必存在的成员污染更干净。但这对你来说是否是一个好的解决方案取决于你想要实现什么。你的用例到底是什么?我觉得很糟糕,因为这是构造函数初始化值的原理。我会保留虚拟方法来重新定义类中的不同行为,而不是按照您的方式使用它。更不用说,如果你有100个类,如果你需要为每个类重新定义这些方法,你将需要编写更多的代码。老实说,如果你给出的例子不仅仅是一个例子,而是一个实际的用例,那么不要使用继承。没有必要为每种动物单独设置一个类别。如果你不打算用每种动物特有的行为来扩展每种动物的类别,那就是这样。然后您可以只使用一个Animal类,并将名称和类别传递给构造函数,然后只使用这个类。但是,如果您计划用更多功能扩展每个动物类,请将成员放在派生类中,并创建一个对所有动物都通用的纯接口抽象类。您确定吗?那对我来说似乎很肮脏-我认为它一点也不脏,它比基类被不必存在的成员污染更干净。但这对你来说是否是一个好的解决方案取决于你想要实现什么。你的用例到底是什么?我觉得很糟糕,因为这是构造函数初始化值的原理。我会保留虚拟方法来重新定义类中的不同行为,而不是按照您的方式使用它。更不用说,如果你有100个类,如果你需要为每个类重新定义这些方法,你将需要编写更多的代码。老实说,如果你给出的例子不仅仅是一个例子,而是一个实际的用例,那么不要使用继承。没有必要为每种动物单独设置一个类别。如果你不打算用每种动物特有的行为来扩展每种动物的类别,那就是这样。然后您可以只使用一个Animal类,并将名称和类别传递给构造函数,然后只使用这个类。但是,如果您计划用更多功能扩展每个动物类,请将成员放在派生类中,并创建一个对所有动物通用的纯接口抽象类。