我正在尝试c++
中的装饰器设计模式。但是,如果没有抽象超类(核心和装饰类都从中继承),我将无法实现它。
我不明白为什么需要抽象超类。
我工作的装饰器示例:
#include <string>
#include <iostream>
using namespace std;
// abstract superclass
class Pizza
{
public:
virtual string GetDescription() = 0;
virtual int GetCost() = 0;
};
// base class that can be extended
class Margharita: public Pizza
{
private:
string description;
int cost;
public:
Margharita(string t, int c){description = t; cost = c;}
string GetDescription(){return(description);}
int GetCost(){return(cost);}
};
// decorator class that extends base class
class ExtraCheese: public Pizza
{
private:
Pizza* pizza;
public:
// constructor
ExtraCheese(Pizza* p) {pizza = p;}
string GetDescription() { return (pizza->GetDescription() + ", Extra Cheese"); }
int GetCost() { return(pizza->GetCost() + 20); }
};
int main()
{
// create decorated object
Pizza* pizza = new ExtraCheese(new Margharita("Margharita", 100));
cout << pizza->GetDescription() << '\n';
cout << pizza->GetCost() << '\n';
}
给出输出:Margharita, Extra Cheese 120
。
如果我删除抽象超类,装饰将停止工作:
#include <string>
#include <iostream>
using namespace std;
// base class that can be extended
class Pizza
{
private:
string description;
int cost;
public:
Pizza(){description = "Pizza"; cost = 100;};
string GetDescription(){return(description);}
int GetCost(){return(cost);}
};
// decorator class that extends base class
class ExtraCheese: public Pizza
{
private:
Pizza* pizza;
public:
// constructor
ExtraCheese(Pizza* p) {pizza = p;}
string GetDescription() { return (pizza->GetDescription() + ", Extra Cheese"); }
int GetCost() { return(pizza->GetCost() + 20); }
};
int main()
{
// create decorated object
Pizza* pizza = new ExtraCheese(new Pizza());
cout << pizza->GetDescription() << '\n';
cout << pizza->GetCost() << '\n';
}
在这种情况下,输出仅显示核心对象(Pizza 100
)的属性。
为什么会这样?
答案 0 :(得分:5)
当删除抽象基类时,您使函数GetDescription
和GetCost
不是虚拟的。因此,它们不会动态分配。这就是pizza->GetDescription()
调用Pizza
成员函数的原因,它是仅基于pizza
的静态类型解析的调用。
您无需具有抽象基础即可使其再次工作,只需动态分配即可,因此只需添加虚拟说明符
class Pizza
{
private:
string description;
int cost;
public:
Pizza(){description = "Pizza"; cost = 100;};
virtual string GetDescription(){return(description);}
virtual int GetCost(){return(cost);}
};
这将允许ExtraCheese
中的优先级被动态调度拾取。您还可以通过使用override
说明符来帮助编译器捕获此类错误。您是否像这样定义ExtraCheese
:
class ExtraCheese: public Pizza
{
private:
Pizza* pizza;
public:
// constructor
ExtraCheese(Pizza* p) {pizza = p;}
string GetDescription() override { return (pizza->GetDescription() + ", Extra Cheese"); }
int GetCost() override { return(pizza->GetCost() + 20); }
};
现代编译器会抱怨您试图覆盖未声明为虚函数的功能。错误会很明显。