让我们有下面的课
class Animal
{
public:
virtual short getFeet() = 0;
virtual void setFeet(short feet) = 0;
};和两个派生类:
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的指针。
int main(int argc, _TCHAR* argv[])
{
Animal *a = new Bird();
std:: cout << a->getFlyingSpeed() << '\t'; // error!
}我认为编译器不是在编译期间检查正确的赋值,但是只有两种类型的运行时检查。但我错了因为..。
错误C2039:
getFlyingSpeed:不是Animal的成员
有任何方法,如何使用一个属性,这不是所有的类,连同一个多态?或者只能强制运行时输入chcek?
也许这个模型不正确。怎么重新设计?
谢谢你的帮助。
发布于 2012-08-13 19:39:57
您的呼叫动物只应提供所有动物(或您希望在您的应用程序中使用的动物)共同的功能。对于并非所有动物共有的其他特性,可以使用多重遗传来实现对子类型动物的期望行为。所以一个子类型可能是FlyingAnimals。
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; }
};您还可以为有脚的动物定义一个子类,等等。
或者,您可以这样构建它,而不是多重继承:
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; }
};然而,在你的主要方法中,你需要定义你怀疑的动物类型。
int main(int argc, _TCHAR* argv[])
{
FlyingAnimal *a = new Bird();
std:: cout << a->getFlyingSpeed() << '\t'; // not an error anymore!
}发布于 2012-08-13 19:43:56
Animal *a = new Bird();赋值是正确的;Bird是从Animal派生的,因此Bird*可以存储在Animal*中。但是指针a的类型是指向Animal的,而不是指向Bird的,因此您只能调用为Animal定义的成员函数。这就是为什么编译器将
a->getFlyingSpeed()getFlyingSpeed不是Animal的成员函数。另一方面,那个电话
a->getFeet()很好,因为getFeet是Animal的成员函数。它将调用在getFeet中定义的Bird版本,因为Bird是a指向的对象的类型。
简而言之,C++是静态类型的;也就是说,类型是在编译时确定的,这就是为什么只能在a上调用Animal成员函数的原因。
发布于 2012-08-13 19:44:42
A)
公开公开setFeet()看起来很奇怪(让我们说这是业余外科医生沙箱),但我建议重新设计对象层次结构,如下所示:
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:
virtual void* extension(int functionId, int param) = 0;是的,很丑,但让你去那里
https://stackoverflow.com/questions/11940916
复制相似问题