首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >C++、对象模型和多态性:运行时检查

C++、对象模型和多态性:运行时检查
EN

Stack Overflow用户
提问于 2012-08-13 19:24:23
回答 7查看 312关注 0票数 3

让我们有下面的课

代码语言:javascript
运行
复制
class Animal
{
  public: 
    virtual short getFeet() = 0;
    virtual void setFeet(short feet) = 0;
};

和两个派生类:

代码语言:javascript
运行
复制
class Bird : public Animal
{
    short flying_speed; 
  public:
    virtual short getFeet() { return 2; }  // always 2 feet
    virtual void setFeet(short feet_) { };
    virtual short getFlyingSpeed() { return flying_speed; }
};

class Mammal : public Animal 
{
    short feet; // whale: 0 feet, human: 2 feet, others: 4 feet
  public:
    virtual short getFeet() { return feets; }
    virtual void setFeet(short feet_) { feet = feet_ };
};

A)一个与对象模型相关的问题:

让我们把注意力集中在房地产方面。如何处理属性脚和方法getFeet()和setFeet()。

一些属于同一类别的动物有不同数量的脚,所以他们使用属性脚和方法getFeet()setFeet()是常见的。

有些动物有同样的足,所以他们不使用自己的属性feet。方法getFeet()返回一个常量,方法setFeet()不执行任何操作。

这个模型是正确的还是任何与可变脚相关的改变都是推荐的(有很多动物没有脚)?

B)一个与多态性相关的问题

一个类别有一些特定的特征;例如,正在飞行的鸟类。所以问他们的飞行速度是有意义的,看看getFlyingSpeed()的方法。

我们希望使用多态性并创建指向Bird的指针。

代码语言:javascript
运行
复制
int main(int argc, _TCHAR* argv[])
{
    Animal *a = new Bird();
    std:: cout << a->getFlyingSpeed() << '\t'; // error!
}

我认为编译器不是在编译期间检查正确的赋值,但是只有两种类型的运行时检查。但我错了因为..。

错误C2039:getFlyingSpeed:不是Animal的成员

有任何方法,如何使用一个属性,这不是所有的类,连同一个多态?或者只能强制运行时输入chcek?

也许这个模型不正确。怎么重新设计?

谢谢你的帮助。

EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2012-08-13 19:39:57

您的呼叫动物只应提供所有动物(或您希望在您的应用程序中使用的动物)共同的功能。对于并非所有动物共有的其他特性,可以使用多重遗传来实现对子类型动物的期望行为。所以一个子类型可能是FlyingAnimals。

代码语言:javascript
运行
复制
class FlyingAnimal
{
  public: 
    virtual short getFlyingSpeed() = 0;
    virtual ~FlyingAnimal(){}

};


class Bird : public Animal, public FlyingAnimal
{
    short flying_speed; 
  public:
    virtual short getFeet() { return 2; }  // always 2 feet
    virtual void setFeet(short feet_) { };
    virtual short getFlyingSpeed() { return flying_speed; }
};

您还可以为有脚的动物定义一个子类,等等。

或者,您可以这样构建它,而不是多重继承:

代码语言:javascript
运行
复制
class FlyingAnimal: public Animal
{
  public: 
    virtual short getFlyingSpeed() = 0;
    virtual ~FlyingAnimal(){}

};


class Bird : public FlyingAnimal
{
    short flying_speed; 
  public:
    virtual short getFeet() { return 2; }  // always 2 feet
    virtual void setFeet(short feet_) { };
    virtual short getFlyingSpeed() { return flying_speed; }
};

然而,在你的主要方法中,你需要定义你怀疑的动物类型。

代码语言:javascript
运行
复制
int main(int argc, _TCHAR* argv[])
{
    FlyingAnimal *a = new Bird();
    std:: cout << a->getFlyingSpeed() << '\t'; // not an error anymore!
}
票数 2
EN

Stack Overflow用户

发布于 2012-08-13 19:43:56

代码语言:javascript
运行
复制
Animal *a = new Bird();

赋值是正确的;Bird是从Animal派生的,因此Bird*可以存储在Animal*中。但是指针a的类型是指向Animal的,而不是指向Bird的,因此您只能调用为Animal定义的成员函数。这就是为什么编译器将

代码语言:javascript
运行
复制
a->getFlyingSpeed()

getFlyingSpeed不是Animal的成员函数。另一方面,那个电话

代码语言:javascript
运行
复制
a->getFeet()

很好,因为getFeetAnimal的成员函数。它将调用在getFeet中定义的Bird版本,因为Birda指向的对象的类型。

简而言之,C++是静态类型的;也就是说,类型是在编译时确定的,这就是为什么只能在a上调用Animal成员函数的原因。

票数 2
EN

Stack Overflow用户

发布于 2012-08-13 19:44:42

A)

公开公开setFeet()看起来很奇怪(让我们说这是业余外科医生沙箱),但我建议重新设计对象层次结构,如下所示:

代码语言:javascript
运行
复制
class Animal
{
public:
    virtual short getFeet() const = 0;
}

class SurgeonDelight : public Animal
{
    short feetNumber;
public:
    short getFeet() const {return feetNumber;}
    virtual void setFeet(short feet) {feetNumber = feet;}
}

然后你继承了所有的动物,有固定数量的脚从Animal,所有其他从SurgeonDelight。我们将setFeet虚拟为其后代,以实现改变脚数的一些副作用。SurgeonDelight隐藏实际的数据成员,以强制执行“更改的单一原因”。

B)

您可以使用RTTI和dynamic_cast,但基本上您应该将Bird构造为Bird

有人告诉我,“如果你必须做dynamic_cast,你的设计很糟糕”。我倾向于同意。我编码了5年以上,一次也没有使用dynamic_cast (因为我们不支持它)。如果你的动物园里有更多的以飞行速度飞行的动物(比如Turtle),你应该在你的层次结构中注入更多的概括层。

我在几个库中看到的另一个不太好的方法是留下"extension“API:

代码语言:javascript
运行
复制
virtual void* extension(int functionId, int param) = 0;

是的,很丑,但让你去那里

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11940916

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档