我有多个(比如说2个)派生自抽象基类的类,比如说Ingredient
。现在,Carrot
和Potato
通过公共继承实现Taste()
的纯虚函数(称为Ingredient
)。现在,假设我想要一个Salt
的类Ingredient
(也就是说,它是从它派生的),但需要调用其姐妹类的Taste()
实现?
基本上,Salt
类稍微修改了其姐妹类的Taste()
实现。
这可以实施吗?如果是这样,怎么样?
这是我想要做的草图:
class Ingredient {
virtual void Taste() = 0;
};
class Carrot : public Ingredient {
void Taste() { printf("Tastes like carrot");}
};
class Potato : public Ingredient {
void Taste() { printf("Tastes like potato"); }
};
class Salt : public Ingredient {
void Taste() { SisterClass->Taste(); printf(" but salty"); }
};
答案 0 :(得分:5)
盐不能合理地提供改良的味道:它需要一种实际的其他成分来加盐。但是其他哪些成分呢?事实上,具有“某种东西,但咸味”味道的不是盐,而是咸味制剂,其中包含另一种成分。这可以通过以下几种方式建模:
此准备字面上包含其他成分,并代理电话。
class SaltedPreparation : public Ingredient {
Ingredient *baseIngredient;
void Taste() { baseIngredient->Taste(); printf(" but salty"); }
};
Tomato tomato;
SaltedPreparation preparation;
preparation.baseIngredient = &tomato;
preparation.Taste();
class SaltedTomato : public Tomato {
void Taste() { Tomato::Taste(); printf(" but salty"); }
};
SaltedTomato tomato;
tomato.Taste();
每次我需要调味时,我都不热衷于编写新课程,所以让我们为此编写一个模板! Mixin模式对于现有类的这种通用修改是典型的。
template <class BaseIngredient>
class Salted : public BaseIngredient {
void Taste() { BaseIngredient::Taste(); printf(" but salty"); }
};
Salted<Tomato> tomato;
tomato.Taste();
所有上述模型都失去了盐本身也应该成为一种成分的事实。这可能没问题,但如果必须怎么办?然后复合图案可能是有用的。我们也将调味料与主要成分区分开来,因为我们不喜欢咸咸盐。
class Seasoning : public Ingredient { };
class Salt : public Seasoning {
void Taste() { printf("salty"); }
};
class SeasonedPreparation : public Ingredient {
Ingredient *ingredient;
Seasoning *seasoning;
void Taste() { ingredient->Taste(); printf(", but "); seasoning->Taste(); }
};
Tomato tomato;
Salt salt;
SeasonedPreparation preparation;
preparation.ingredient = &tomato;
preparation.seasoning = &salt;
preparation.Taste();
我现在有点饿了。
答案 1 :(得分:1)
Salt
无法修改其他类的实现。但Salt
可以指向另一个Ingredient
的指针,例如:
class Salt : public Ingredient
{
private:
Ingredient *OtherIngredient;
public:
Salt(Ingredient *AOther) : OtherIngredient(AOther) {}
virtual void Taste() { OtherIngredient->Taste(); printf(" but salty"); }
};
然后你可以这样做:
Potato potato;
Salt salt(&potato);
salt.Taste();
但这不是真的有意义,是吗?盐味道不像马铃薯,但马铃薯味道咸。所以,我可能会采取不同的方法:
#include <vector>
class Ingredient
{
public:
virtual void Taste() = 0;
};
class Seasoning : public Ingredient
{
};
class SeasonableIngredient : public Ingredient
{
protected:
std::vector<Seasoning*> seasonings;
virtual void TastesLike() = 0;
public:
virtual void Taste()
{
printf("Tastes like ");
TastesLike();
if (!seasonings.empty())
{
std::vector<Seasoning*>::iterator iter = seasonings.begin();
printf(" but ");
iter->Taste();
++iter;
while (iter != seasonings.end())
{
printf(" and ");
iter->Taste();
++iter;
}
}
}
void AddSeasoning(Seasoning *seasoning) { seasonings.push_back(seasoning); }
};
class Carrot : public SeasonableIngredient
{
protected:
virtual void TastesLike() { printf("carrot"); }
};
class Potato : public SeasonableIngredient
{
protected:
virtual void TastesLike() { printf("potato"); }
};
class Salt : public Seasoning
{
public:
void Taste() { printf("salty"); }
};
class Pepper : public Seasoning
{
public:
void Taste() { printf("peppery"); }
};
Potato potato;
Salt salt;
Pepper pepper;
Potato.AddSeasoning(&salt);
Potato.AddSeasoning(&pepper);
potato.Taste();