有没有办法根据派生类的可能性值范围来限制对象参数?

Posted

技术标签:

【中文标题】有没有办法根据派生类的可能性值范围来限制对象参数?【英文标题】:Is there a way to restrict objects parameters according to a derived class range of possibility values? 【发布时间】:2019-08-05 13:15:08 【问题描述】:

我正在尝试创建一个动物数据库。如何让每个动物物种都有一些具有固定值的参数和一些具有一系列可能值的参数,以便每个物种的个体(对象)可以从中“选择”?

从基本的 OOP 开始,我可以有一个 Dog 类,包含对象“Rex”和“Fido”,然后是一个 Bird 类,包含对象“Rocky”和“Coco”。我为它们创建了一个基类,Animal 类,其参数对所有人都是通用的,如下所示。

当我创建 Dog 类时,我如何修复我希望所有狗都拥有的 Body_Parts(所有狗都有头、腿、尾巴等,但没有翅膀)以及如何为每个狗设置一系列可能的值可供选择的 Dog 类对象(因为狗可能是黑色、棕色或白色,也可能是两者的混合,但绝不是绿色或蓝色)?

#include <string>
#include <vector>

enum class Body_Part

    HEAD,
    WING,
    ...,
    TAIL;
;

enum class Color

    BLACK,
    RED,
    WHITE,
    BROWN,
    GREEN
    BLUE;
;

class Animal

public:
    Animal();
    ~Animal();

private:
    std::string m_Species;
    std::vector<Body_Part> m_Limbs;
    std::vector<Color> m_Colors;

【问题讨论】:

为什么不使用字符串数组/向量?是的,它们占用更多空间,但除非您使用嵌入式硬件,否则您永远不会注意到它,并且它允许您拥有无限的灵活性。 您是否也想对诸如“只有带翅膀的独角兽可以是蓝色的”之类的要求进行建模?或者这个列表是每个子类固定的? @Werneck 好吧,除了可能的数量之外,身体部位不应该是用户可以控制的东西。你有一张&lt;string, int&gt; 的地图,然后用户可以控制该对象有多少条腿/眼睛/翅膀,但不能更改它的构建属性。 您可能需要多考虑一下您的项目设计。你应该能够创建一个Animal 实例吗?或仅例如CatDog 实例?然后确保没有人可以创建Animal 类的实例(使构造函数受保护),并在子类CatDog 中初始化颜色和正文部分。 您可以使用默认值填充地图,然后让用户能够更改这些值,例如std::map&lt;std::string, int&gt; body_parts"legs", 4,"eyes",2."ears",2, ... 【参考方案1】:
class Animal

public:
    Animal(std::vector<Color> allowedColors, std::vector<BodyPart> requiredLimbs)
      : m_Limbs(requiredLimbs), m_colors(allowedColors)
    
// ...
;

然后每个派生类必须在构造时决定什么是允许的,什么是不允许的。

但是,此代码中存在一些混淆,可能需要完全不同的设计。

一个动物实例(“Rocky”)可以有多个肢体,但只有一种颜色(我猜?)。那么为什么Animal 的每个实例都有一个颜色列表呢?

分配/提供肢体和颜色应该是Animal 基类或每个派生类的工作吗?谁是此代码的用户,他们希望做什么?设置肢体和颜色?如果是这样,这应该是一个Animal 接口还是每个Dog 都有一个方法来决定自己的颜色?

肢体是“必需”列表(给定动物类型的每个实例都需要有所有这些肢体),但颜色是“允许”列表(每个给定的动物类型需要恰好有一种这些颜色)。这是当前未在代码中反映的含义上的显着差异。

但是问题变成了“拥有”给定肢体的含义。 Unicorn 是否完整,因为它的 m_Limb 列表包含两个 WINGs?如果每个独角兽都需要它,这有什么帮助? m_Limb 列表是否说明了动物实例的任何内容,还是实际上只是描述了动物的种类

在我看来,所需肢体和允许颜色的列表不应该存储在每个动物实例中,而应该是派生类型的某些属性(例如Dog、@987654331 @)。当您想为 types 注入属性时,您往往会离开 OOP 领域并进入模板领域...

【讨论】:

1. "Rocky" 将是一个 Bird 实例,它来自于 animal。鸟类有固定的身体部位:2个翅膀、2个眼睛、1个尾巴等;它们可能有多种颜色。 2.我认为 Animal 类是每个子类的所有可能性的提供者,但仅适用于所有动物都会拥有的东西(比如颜色,尽管每种特定动物可能有什么颜色或颜色)。四肢不会固定,它们固定在每只动物身上。每个物种的每个个体的颜色都可以更改,但仅限于该物种可能更改的颜色(狗可以是棕色、白色或两者兼有;绝不是蓝色)。 3.我不知道如何在我的代码中反映这种差异。此外,颜色作为允许列表允许动物选择多种颜色,前提是该物种允许它们。 4. 另外,我并不关心身体部位的数量,只要他们有那个部位。我相信动物特征只是描述了动物,但我不确定你在那里问了什么,抱歉。如果每只独角兽都有一个翅膀“身体部位”而狗没有,那么独角兽可以飞而狗不能。我认为这是描述性的。没有把握。 5. 我会检查模板,因为您可能已经达到了问题的“更好的方法”部分。【参考方案2】:

显然,我正在尝试的并不是真正需要的。与朋友交谈后,他说,因为我正在做一个数据库,这一切都在用户界面中完成,我不需要一个类,它的子类。他说我将为每个“类和子类”创建一个简单的类,仅用于获取用户输入和记录到文件。在向用户加载屏幕上的信息时应添加限制。

使用上面的例子,我会在一个文件中包含狗和鸟的数据,在一个类似 txt 的文件中思考:

(animal,body1-body2-...-bodyN,color1-color2-...-colorN)

(dog,head-teeth-tail,black-brown-white)
(bird,head-beak-wing-tail,black-white-yellow-green-red)

当我尝试添加“狗对象”时,例如“Fido”,屏幕上只会显示狗的信息,因此“Fido”将被记录为:

(Fido,head-teeth-tail,black)

这样我需要为每个动物物种创建一个类,然后为每个物种的个体创建另一个类,并将约束添加到用户而不是类。 谢谢大家,反正对大家都有帮助。

【讨论】:

以上是关于有没有办法根据派生类的可能性值范围来限制对象参数?的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法在不知道派生类型的情况下将包含派生指针的 std::any 转换为基指针?

C++中的派生类,可以不定义对象直接调用基类的成员和调用自己的成员函数嘛???

关于C++基类、派生类的引用和指针

6多态性-3虚函数

有没有办法请求特定于存储桶的读取范围?

CRTP:根据派生类内容启用基类中的方法