C++,使用基类指针存储子类和使用派生类方法的策略
C++,Strategy to use base class pointer storing subclasses and use the derived classes' method
基类是程序中每个类的基,它提供x_pos和y_pos。
不同的人和动物可以创建为动物和人的子类
在我的例子中,我创建了王班
我有以下课程
#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;};
};
问题是,出于某种原因,我必须有一个Base指针来存储人或动物。(例如,地板上有一个"底座")
class Floor{
Base *bs;
public:
void haveFun(){
// bs->Wang::havefun();
// I want to achieve this goal
}
}
如何在不向下投射的情况下访问人/动物和王级别的方法
有什么策略我可以在这里应用吗
(我有点认为vistor的模式可能会应用于此,但我不知道如何应用)
在这里使用双重调度/访问者有点尴尬,因为为Floor
提供的代码已经存储了Base*
,并且只有一个继承层次结构。在没有进行侵入性设计更改的情况下,类型信息在这一点上已经有点丢失了。
无论使用什么,通常都需要基于实际子类型的某种形式的分支。它可能是第二个虚拟调度,可能是查看类型信息的if/else
语句,可能是对dynamic_casts
的尝试,并捕获bad_cast
(用于引用)或对照nullptr
检查结果以查找指针。
在您的情况下,如果您想避免dynamic_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;}
...
}
这将CCD_ 8耦合到CCD_。CCD_ 10仍然可以以其他方式(包括编译时报头依赖性)与CCD_ 11解耦。
这确实意味着您必须为要单独处理的每个子类型向Base
添加代码,但无论您使用什么(包括访问者),通常都需要在某个地方添加代码。
class Floor{
Base *bs;
public:
void haveFun(){
// If `bs` is a person, invoke `haveFun`.
Person* person = bs->person();
if (person)
person->haveFun();
}
}
这种方法的缺点是,要通过指向Base*
的指针在子类型级别上处理的每个新子类型都需要向Base
添加新函数(尽管向Base
添加新函数不太容易受到脆弱基类综合症的影响)。好处是,你可以,比如说,大幅更改Person
或Animal
的接口,而不必更新Base
。针对新的需求进行扩展是相当容易的,并且避免了降级(可以说,降级可能更容易被滥用)。这使得设计比在类型之间转换更明确地说明什么是合法行为,并避免了潜在的RTTI要求(如果出于某种原因需要考虑的话)。
如果你想避免下转换(这是一件合理的事情,尽管这不是绝对必要的,因为dynamic_cast<>将提供安全的下转换),你有两个选项:
1) 将您可能希望在基类中调用的所有方法声明为虚拟方法。定义那些什么都不做或返回错误代码(或类似代码)的方法的基类实现,这样,当您在不适当类型的对象上调用这些方法时,就不会发生有害的事情。
或
2) 在Floor类中保留多个指针;每种类型的对象都有一个,你可能想把它放在那里。这样,当你想调用haveFun()时,你就知道你的Person对象可以通过(Person*)指针而不是(Animal*)指针访问。如果希望每个楼层约束仅强制一个对象,请确保在设置"人物"指针时清除"动物"指针,反之亦然。
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 从基类实例调用派生类方法而不进行强制转换
- C++ 使用派生类方法更改基类数据成员
- 将派生类方法与基类unique_ptr一起使用
- 使用派生类C++方法的超类
- 从库类扩展,然后如何让库调用派生类方法
- 当应该调用派生类方法时,为什么要调用基类方法
- 抽象类的需求是什么?为什么要通过其基类访问派生类方法?在C++
- 如何轻松地将 Base 方法重定向到相同的派生类方法
- Gmock Base类方法中的派生类方法
- 如何调用精确派生类方法?
- 为什么可以从实例化基类对象的投射指针调用非静态派生类方法
- C++使用基类指针访问派生类方法
- 调用派生类方法时出现分段错误
- 从基类析构函数调用派生类方法
- 基类的指针数组:如何调用唯一的派生类方法
- 派生类方法的默认参数的最佳实践
- 从基类实例调用派生类方法
- C++ 继承:指向基类的派生类指针调用派生类方法
- 虚函数未解析为大多数派生类方法