Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ionic-framework/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ C++;,使用基类指针存储子类并使用派生类的策略';方法_C++_Inheritance - Fatal编程技术网

C++ C++;,使用基类指针存储子类并使用派生类的策略';方法

C++ C++;,使用基类指针存储子类并使用派生类的策略';方法,c++,inheritance,C++,Inheritance,基类是程序中每个类的基,它提供x_pos和y_pos。 Animal(为清晰起见删除)和Person是基类的直接子类 不同的人和动物可以创建为动物和人的子类 在我的示例中,我创建了Wang类 我有以下课程 #include <iostream> class Base{ protected: int x_pos; int y_pos; public: Base(int x,int y): x_pos(x), y_pos(y){}; virtu

基类是程序中每个类的基,它提供x_pos和y_pos。
Animal(为清晰起见删除)和Person是基类的直接子类
不同的人和动物可以创建为动物和人的子类
在我的示例中,我创建了Wang类

我有以下课程

#include <iostream>
class Base{ 
protected:    
    int x_pos;
    int y_pos;
public:
    Base(int x,int y): x_pos(x), y_pos(y){};
    virtual ~Base(){};
    int getX(){return x_pos;};
    int getY(){return y_pos;};
};

class Person : public Base{
protected:
    char sex;
public:
    Person(int x,int y,char sex):Base(x,y), sex(sex){};
    virtual ~Person(){};
    char getSex(){return sex;};
    virtual void haveFun() = 0;
};

class Wang : public Person{
public:
    Wang(int x,int y,char a): Person(x,y,a){};
    ~Wang(){};
    void haveFun(){ std::cout << "Wang is coding" << std::endl;};
};
我如何才能在不向下投射的情况下访问人/动物和王级别的方法
有什么策略可以在这里应用吗?

(我认为vistor的模式可能适用于这里,但我不知道如何使用)

如果您想要避免向下投射(这是一个合理的选择,尽管这不是严格必要的,因为动态向下投射将提供安全的向下投射),您有两个选择:

1) 将基类中可能要调用的所有方法声明为虚拟方法。定义那些不执行任何操作或返回错误代码(或类似代码)的方法的基类实现,以便在对不适当类型的对象调用这些方法时,不会发生有害的情况


2) 在课堂上保持多个指针;对于您可能希望保存在其中的每种类型的对象,都有一个。这样,当您想调用haveFun()时,您就知道您的Person对象可以通过(Person*)指针而不是(Animal*)指针访问。如果您想强制每个楼层只有一个对象约束,请确保在设置人员指针时清除动物指针,反之亦然。

在此处使用双重分派/访问者有点尴尬,因为为
楼层提供的代码已经存储了
基本*
,并且只有一个继承层次结构。类型信息在这一点上已经有点丢失了,没有一个相当侵入性的设计更改

无论您使用什么,通常都需要基于实际子类型的某种形式的分支。它可能是第二个虚拟分派,可能是查看类型信息的
if/else
语句,可能是尝试
dynamic\u cast
,或者捕获
bad\u cast
(用于引用),或者针对
nullptr
检查指针的结果

在您的情况下,如果您希望避免
dynamic\u cast
/RTTI并保持代码基本不变,我实际上会建议这样做:

class Animal;
class Person;

class Base{
public:
    ...
    virtual Person* person() {return nullptr;}
    virtual Animal* animal() {return nullptr;}
    ...
}

class Person: public Base{
public:
    ...
    Person* person() override {return this;}
    ...
}

class Animal: public Base{
public:
    ...
    Animal* animal() override {return this;}
    ...
}
这将
人/动物
耦合到
,但仅在某种符号级别<代码>基
仍然可以通过其他方式(包括编译时头依赖项)与人/动物解耦

这确实意味着您必须为要单独处理的每个子类型向
Base
添加代码,但无论您使用什么(包括访问者),您通常都需要在某个地方这样做


这种方法的缺点是,要通过指向
Base*
的指针在子类型级别上处理添加的每个新子类型都需要向
Base
添加新函数(尽管向
Base
添加新函数并不容易受到脆弱基类综合症的影响)。这样做的好处是,您可以大大更改
Person
Animal
的界面,而不必更新
Base
。它很容易根据新的需求进行扩展,并避免了向下转换(这可能更容易被误用)。这使得设计对于什么是合法行为比在类型之间转换更加明确,并且避免了潜在的RTTI要求(如果出于某种原因这是一个问题)。

仍然存在编译错误。@PaulEvans更正。谢谢你不恰当地使用了继承。举例说明。。。。从什么时候起,“王”就变成了另一类人了?猫和动物之间的关系是显而易见的——猫是一种特殊类型的动物。然而,王只是一个特定个体的名字,而不是某个特定类型的人。@Peter我这样做是因为不同的人有不同的方式来享受乐趣()。在一些游戏中把王当作英雄。嗯,这是你的问题。英雄主义是一种情景属性(例如,面对火灾时的勇敢、因勇敢而获得奖励或特权等),而不是定义不同的人的子类。谢谢你的回答。如果我在Person和Wang之间再上一节课呢。例如,GoodPerson,它有一个字段(moneyDevate:int)和一个方法(getMoneyDevate():int)。我可以在基类中放一个虚拟的getMoneyVedacted():int吗?当然可以;可以让基类方法只返回0或其他值。当然,这样做的最终缺点是基类可能会开始变得非常混乱,有很多方法,但它会起作用。
class Animal;
class Person;

class Base{
public:
    ...
    virtual Person* person() {return nullptr;}
    virtual Animal* animal() {return nullptr;}
    ...
}

class Person: public Base{
public:
    ...
    Person* person() override {return this;}
    ...
}

class Animal: public Base{
public:
    ...
    Animal* animal() override {return this;}
    ...
}
class Floor{
    Base *bs;
public:
    void haveFun(){ 
      // If `bs` is a person, invoke `haveFun`.
      Person* person = bs->person();
      if (person)
          person->haveFun();
    }
}