最好的方法访问方法的派生类c++
best way of accessing method on derived class C++
我有一些类型都是Zoo
的不同对象,它们有一个成员变量Collection = vector<Animal>
。我有一个动物园的例子,所有的元素都是动物,一个是所有的元素都是Birds
,一个是所有的元素都是Bats
。Birds
和Bats
都来源于Animals.
我希望有一个方法fly()
,我可以调用所有的鸟类和蝙蝠,但我不确定这样做的最好方法。当我在我的鸟/蝙蝠动物园里循环时,我是否应该直接投射?这样的:
Bird thisBird = static_cast<Bird>(Collection[i]);
thisBird.fly();
…或者我能以某种方式在Animal上有一个虚拟函数,它只在派生的类上实现?
想法,以及为什么它们是"好代码"的理由,欢迎!
哦,是的,Animal
可以有一个虚拟函数:
virtual void move(){}
virtual void fly(){}
你命令狗飞,它什么也不做。当你命令一只鸟移动时,它也可以呼叫fly()
。
为会飞的动物定义正确的fly()
Colection[i]->fly()
将做正确的事情。这样你的代码就会很简单。
但是要做到这一点,你的集合必须收集指向动物的指针,而不仅仅是动物对象。例如:
#include <vector>
#include <memory>
#include <iostream>
using namespace std;
struct Animal{virtual void fly(){}};
struct Bird:public Animal{void fly(){cout<<"flyn";}};
int main()
{
vector<unique_ptr<Animal>> Colection(1);
Colection[0].reset( new Bird );
Colection.push_back(unique_ptr<Animal>(new Bird) );
Colection.push_back(unique_ptr<Animal>(new Animal) );
Colection[0]->fly();
Colection[1]->fly();
Colection[2]->fly();
}
阅读其他答案,我可以建议你实现像
struct Animal {virtual bool fly(){return false; }};
struct Bird:public Animal{bool fly(){cout<<"flyn";return true;}};
你不需要单独的canFly
不是所有的动物都会飞,所以没有必要为了通用的目的而尝试执行特定的行为(即所有动物之间不常见的行为)。如果你有一个Animal类(或它们的派生类)的集合,它的目的是允许它们做一个共同的行为(由每个派生类实现不同)。
你可以实现一个FlyAble
接口(即抽象类),并且只对真正会飞的动物进行扩展。然后把它们保存在另一个为这类动物指定的收藏中(即<FlyAble
>)。
你可能不希望像Bird
和Bat
这样的层次结构产生于Animal
,而没有在较低的类中声明fly()
方法。这样你就失去了统一的层次结构。
你可以做:
class Animal {
virtual bool canFly() { return false; }
virtual void fly() {throw Exception( "Sorry babe, I don't fly"); }
}
在Bird
和Bat
中重写fly
。
这将导致您为狗和猫实现fly()
方法,这可能是您不想要的。也许你可以创建一个新的类Flyer
来声明这个方法:
class Flyer : public Animal {
virtual void fly() = 0;
}
class Bat : public Flyer {}
class Bird : public Flyer {}
这将与Reptile
, Mammal
等更详细的生物分类不一致。
另一个技巧可能是提出像move()
这样的方法,dog将其实现为run()
, bird将其实现为fly()
,它们都有统一的接口。
另一件事是,我认为狗是否会飞是一个有效的问题,所以我认为像Dog.canFly()
这样的方法应该在你的代码中实现,作为动物的一部分。
考虑到所有这些因素,我会选择这个:
// Your base animal
class Animal {
virtual bool canFly() {return false;}
};
// Any animal that could fly, just abstract class
class Flyer {
virtual void fly() = 0;
}
// Ants, flies etc.; real biological hierarchy
class Insect : public Animal {}
class Mammals : public Animals {}
class Birds : public Animals {}
// And now flying bird :
class Bird : public Birds, public Flyer {
virtual bool canFly() {return true; }
virtual void fly() {...}
}
// And flying insect
class Fly : public Insect, public Flyer {
virtual bool canFly() {return true; }
virtual void fly() {...}
}
你可以这样做(基于这个答案,恐怕你必须使用指针):
if( Collection[i]->canFly()){
Flyer *thisBird = static_cast<Flyer*>(Collection[i]);
}
您也可以从Animal
派生Flyer
并使用虚拟继承,但这被称为"可怕的钻石",这不是一个好的实践,但值得一读。
正如Ricibob在注释中指出的那样,Flyer
应该指定canFly()
,这将在简单的示例中:
class Flyer {
public:
virtual bool canFly() const {return true;}
virtual void fly() {cout << "Flying" << endl; }
};
Bird b;
cout << "Can fly: " << b.canFly() << endl;
// Error 1 error C2385: ambiguous access of 'canFly'
但是如果您将Flyer
从Animal
和Bird
交付给Birds
和Flyer
类:
class Animal {
public:
virtual bool canFly() const {return false;}
};
class Flyer : virtual Animal {
public:
virtual bool canFly() const {return true;}
virtual void fly() {cout << "Flying" << endl; }
};
class Bird : virtual public Birds, virtual public Flyer {
};
// Warning 1 warning C4250: 'Bird' : inherits 'Flyer::Flyer::canFly' via dominance
现在canFly()
返回1
,但代码似乎不对。
此时……您可以为每个子类(或大型组)手动指定canFly()
,或者从Flyers
交付Birds
(例如Chicken
就不正确),或者交付新的子类:
class FlyingBrids : public Birds, public Flyer /* Flyer not delivered from Animal */ {
virtual bool canFly() const {return true;}
};
注意Flyer
仍然很重要,因为Fly
是从Insect
传递过来的。
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 初始化具有非默认构造函数的std::数组项的更好方法