[英]Deriving an abstract class from concrete class
Let's say we have a concrete class Apple
. 假设我们有一个具体的
class Apple
。 (Apple objects can be instantiated.) Now, someone comes and derives an abstract class Peach
from Apple. (可以实例化Apple对象。)现在,有人来从Apple派生抽象
class Peach
。 It's abstract because it introduces a new pure virtual function. 它是抽象的,因为它引入了新的纯虚函数。 The user of Peach is now forced to derive from it and define this new function.
现在,Peach的用户被迫从中派生并定义此新功能。 Is this a common pattern?
这是常见的模式吗? Is this correct to do?
这是正确的吗?
Sample: 样品:
Now let's say we have a concreteclass Apple { public: virtual void MakePie(); // more stuff here };
class Peach : public Apple { public: virtual void MakeDeliciousDesserts() = 0; // more stuff here };
class Berry
.
class Berry
。
Someone derives an abstract class Tomato
from Berry.
class Tomato
。
It's abstract because it overwrites one of Berry's virtual functions, and makes it pure virtual.
Sample: 样品:
Note: The names are contrived and do not reflect any actual code (hopefully).class Berry { public: virtual void EatYummyPie(); // more stuff here };
\n\n
class Tomato : public Berry { public: virtual void EatYummyPie() = 0; // more stuff here };
Re Peach from Apple: 来自苹果的Re Peach:
Re Tomato from Berry: 来自浆果的Re Tomato:
Juice()
- imposes certain requirements and makes certain promises. Juice()
-提出了一定的要求并做出了一定的承诺。 Derived classes' implementations of Juice()
must require no more and promise no less. Juice()
必须没有更多要求,也不会更少承诺。 Then a DerivedTomato IS-A Berry and code which only knows about Berry is safe. Possibly, you will meet the last requirement by documenting that DerivedTomatoes must call Berry::Juice()
. 通过记录DerivedTomatoes必须调用
Berry::Juice()
,可能会满足最后一个要求。 If so, consider using Template Method instead: 如果是这样,请考虑改用Template Method:
class Tomato : public Berry
{
public:
void Juice()
{
PrepareJuice();
Berry::Juice();
}
virtual void PrepareJuice() = 0;
};
Now there is an excellent chance that a Tomato IS-A Berry, contrary to botanical expectations. 现在,极有可能番茄IS-A浆果违反了植物学的预期。 (The exception is if derived classes' implementations of
PrepareJuice
impose extra preconditions beyond those imposed by Berry::Juice
). (例外是,如果派生类的
PrepareJuice
的实现强加了Berry::Juice
施加的前提以外的其他前提)。
It would seem to me like an indication of a bad design. 在我看来,这似乎表明设计不好。 Could be forced if you wanted to take a concrete definition from a closed library and extend it and branch a bunch of stuff off it, but at that point I'd be seriously considering the guideline regarding Encapsulation over Inheritance.. If you possibly can encapsulate, you probably should.
如果您想从一个封闭的库中获取一个具体的定义并对其进行扩展,并从中分支出很多东西,可能会被强制执行,但是那时候我将认真考虑有关继承封装的准则。 ,您可能应该。
Yeah, the more I think about it, this is a Very Bad Idea. 是的,我想得越多,这是一个非常糟糕的主意。
Not necessarily wrong , but definitely smelly. 不一定是错误的 ,但肯定是臭的。 Especially if you leave the fruit out in the sun for too long.
特别是如果您将水果放在阳光下太长时间。 (And I don't think my dentist would like me eating concrete apples.)
(而且我认为我的牙医不希望我吃水泥苹果。)
Though, the main thing I see here that's smelly isn't so much the abstract class derived from a concrete class, but the REALLY DEEP inheritance hierarchy. 虽然,我在这里看到的主要问题不是从具体类派生的抽象类,而是真正的继承层次。
EDIT: re-reading I see that these are two hierarchies. 编辑:重新阅读我看到这是两个层次结构。 All the fruit stuff got me mixed up.
所有的水果东西使我感到困惑。
If you use the recommended practice of having inheritance model "is-a" then this pattern would pretty much never come up. 如果您使用具有继承模型“ is-a”的推荐做法,则这种模式几乎永远不会出现。
Once you have a concrete class, you are saying that it is something that you can actually create an instance of. 一旦有了具体的类,您就可以说它实际上是您可以创建其实例的东西。 If you then derive an abstract class from it, then something that is an attribute of the base class is not true of the derived class, which should set of klaxons that something's not right.
如果然后从中派生一个抽象类,则作为基类的属性的某些东西对派生类而言并不正确,派生类中的klaxons应该是不正确的。
Looking at your example, a peach is not an apple, so it should not be derived from it. 在您的示例中,桃子不是苹果,因此不应衍生自它。 Same is true for Tomato deriving from Berry.
源自浆果的番茄也是如此。
This is where I would usually advise containment, but that doesn't even seem to be a good model, since an Apple does not contain a Peach. 我通常会在这里建议围堵,但这似乎并不是一个好的模型,因为Apple不包含Peach。
In this case, I would factor out the common interface -- PieFilling or DessertItem. 在这种情况下,我将排除常见的接口-PieFilling或DessertItem。
a bit unusual, but if you had some other subclass of the base class and the subclasses of the abstract class had enough common stuff to justify the existance of the abstract class like: 有点不寻常,但是如果您还有基类的其他子类,并且抽象类的子类具有足够的通用知识来证明抽象类的存在,例如:
class Concrete
{
public:
virtual void eat() {}
};
class Sub::public Concrete { // some concrete subclass
virtual void eat() {}
};
class Abstract:public Concrete // abstract subclass
{
public:
virtual void eat()=0;
// and some stuff common to Sub1 and Sub2
};
class Sub1:public Abstract {
void eat() {}
};
class Sub2:public Abstract {
void eat() {}
};
int main() {
Concrete *sub1=new Sub1(),*sub2=new Sub2();
sub1->eat();
sub2->eat();
return 0;
}
Hmmm...by thinking "what a....." for a couple of seconds, I come to a conclusion it is not common... Also, I would not derive Peach from Apple and Tomato from Berry...do you have any better example?:) 嗯...通过思考“什么.....”几秒钟,我得出一个结论,这并不常见...而且,我不会从苹果中得到桃子,从浆果中得到番茄...你有更好的例子吗?
It's a lot of weird shit you can do in C++...I can't even think of 1% of it... 您可以在C ++中做很多奇怪的事...我什至都不会想到其中的1%...
About override a virtual with a pure virtual, you can probably just hide it and it will be really weird... 关于使用纯虚拟机覆盖虚拟机,您可能只是将其隐藏,这真是很奇怪。
If you can find a stupid C++ compiler that would link this function as a virtual, then you will get runtime pure virtual function call... 如果您可以找到一个愚蠢的C ++编译器来将该函数链接为虚函数,那么您将获得运行时纯虚函数调用...
I think this can only be done for a hack and I have no idea what kind of hack really... 我认为这只能针对骇客,我不知道到底是哪种骇客...
To answer your first question, you can do this since users of Apple, if given a concrete instance derived from Peach will not know any different. 要回答您的第一个问题,您可以这样做,因为Apple用户(如果给出了派生自Peach的具体实例将不会有任何不同)。 And the instance will not know its not an Apple (unless there are some virtual functions from Apple that are overridden that you didn't tell us about).
并且该实例将不会知道它不是Apple(除非您没有告诉我们有关Apple的一些虚拟功能的说明,这些虚拟功能将被覆盖)。
I can't yet imagine how useful it would be to override a virtual function with a pure virtual one - is that even legal? 我还无法想象用纯虚函数覆盖虚函数会多么有用-甚至合法吗?
In general you want to conform with Scott Meyers "Make all non-leaf classes abstract" item from his books. 通常,您要遵循Scott Meyers的著作中的“使所有非叶类抽象化”项目。
Anyway, apart from that what you describe seems to be legal - its just that I can't see you needing it that often. 无论如何,除了您描述的内容似乎是合法的-只是我看不到您经常需要它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.