c#试图理解组合,但我的包装器对象正在访问基类字段,而不是使用派生实现
意式浓缩咖啡将作为成分,摩卡咖啡将作为包装。 现在,当我不使用合成进行实例化时,代码按预期执行并返回描述:Espresso:c#试图理解组合,但我的包装器对象正在访问基类字段,而不是使用派生实现,c#,C#,意式浓缩咖啡将作为成分,摩卡咖啡将作为包装。 现在,当我不使用合成进行实例化时,代码按预期执行并返回描述:Espresso: public abstract class Beverage { public string description = "Unknown Beverage"; public string GetDescription() { return description; } } public abstract class Co
public abstract class Beverage
{
public string description = "Unknown Beverage";
public string GetDescription()
{
return description;
}
}
public abstract class CondimentDecorator : Beverage
{
public abstract new string GetDescription();
}
public class Espresso : Beverage
{
public Espresso()
{
description = "Espresso";
}
class Mocha : CondimentDecorator
{
Beverage beverage;
public Mocha(Beverage beverage)
{
this.beverage = beverage;
}
public override string GetDescription()
{
return beverage.GetDescription() + ", Mocha";
}
但是,当我使用composition时,将访问饮料基类中的饮料描述字段,程序将返回描述“Unknown beverage”。但是,我希望得到输出:“Espresso,Mocha”
这是因为
Beverage
中的GetDescription
方法不是虚拟的。编写beverage.GetDescription()
时,编译器查看并看到beverage
的类型是beverage
,然后看到它有一个非虚拟的GetDescription
方法。由于它不是虚拟的,因此不会调用派生的GetDescription
你想要的是更像这样的东西:
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
Console.WriteLine(beverage2.GetDescription());
这是因为
Beverage
中的GetDescription
方法不是虚拟的。编写beverage.GetDescription()
时,编译器查看并看到beverage
的类型是beverage
,然后看到它有一个非虚拟的GetDescription
方法。由于它不是虚拟的,因此不会调用派生的GetDescription
你想要的是更像这样的东西:
Beverage beverage2 = new Espresso();
beverage2 = new Mocha(beverage2);
Console.WriteLine(beverage2.GetDescription());
每当一个类定义一个虚拟函数(或方法)时,大多数编译器都会向该类添加一个隐藏的成员变量,该变量指向一个指向(虚拟)函数的指针数组,称为虚拟方法表(VMT或Vtable)。这些指针在运行时用于调用适当的函数实现,因为在编译时,可能还不知道是调用基函数还是由从基类继承的类实现的派生函数。
@凯指出了问题所在。该方法需要定义为虚拟。然后运行时知道查找运行时类型的覆盖方法,在本例中为Moccha。另外,若调味品装饰师是抽象的,那个么就不需要重新定义调味品装饰师
public abstract class Beverage
{
public string description = "Unknown Beverage";
public virtual string GetDescription()
{
return description;
}
}
public abstract class CondimentDecorator : Beverage
{
public override string GetDescription()
{
return GetDescriptionOverride();
}
protected abstract string GetDescriptionOverride();
}
这样做,您将看到输出
public abstract class Beverage
{
public string description = "Unknown Beverage";
public virtual string GetDescription()
{
return description;
}
}
public abstract class CondimentDecorator : Beverage
{
}
//no change to the rest
...
每当一个类定义一个虚拟函数(或方法)时,大多数编译器都会向该类添加一个隐藏的成员变量,该变量指向一个指向(虚拟)函数的指针数组,称为虚拟方法表(VMT或Vtable)。这些指针在运行时用于调用适当的函数实现,因为在编译时,可能还不知道是调用基函数还是由从基类继承的类实现的派生函数。
@凯指出了问题所在。该方法需要定义为虚拟。然后运行时知道查找运行时类型的覆盖方法,在本例中为Moccha。另外,若调味品装饰师是抽象的,那个么就不需要重新定义调味品装饰师
public abstract class Beverage
{
public string description = "Unknown Beverage";
public virtual string GetDescription()
{
return description;
}
}
public abstract class CondimentDecorator : Beverage
{
public override string GetDescription()
{
return GetDescriptionOverride();
}
protected abstract string GetDescriptionOverride();
}
这样做,您将看到输出
public abstract class Beverage
{
public string description = "Unknown Beverage";
public virtual string GetDescription()
{
return description;
}
}
public abstract class CondimentDecorator : Beverage
{
}
//no change to the rest
...
在下面这行中,您隐藏了基类上的GetDescription方法
"Espresso, Mocha"
在第二个示例中,您看到了问题所在,您将变量键入为。因此,最终将在基类上调用该方法
举个简单的例子:
public abstract new string GetDescription();
然后尝试以下更改:
public class First
{
public string GetName()
{
return "First";
}
}
public class Second : First
{
public new string GetName()
{
return "Second";
}
}
public static class Program
{
public static void Main(string[] args)
{
Second second = new Second();
Console.WriteLine(second.GetName());
// Prints "Second"
First first = second;
Console.WriteLine(first.GetName());
// Prints "First"
Console.ReadKey();
}
}
您会发现它两次都是第二次打印。下面一行隐藏了基类上的GetDescription方法
"Espresso, Mocha"
在第二个示例中,您看到了问题所在,您将变量键入为。因此,最终将在基类上调用该方法
举个简单的例子:
public abstract new string GetDescription();
然后尝试以下更改:
public class First
{
public string GetName()
{
return "First";
}
}
public class Second : First
{
public new string GetName()
{
return "Second";
}
}
public static class Program
{
public static void Main(string[] args)
{
Second second = new Second();
Console.WriteLine(second.GetName());
// Prints "Second"
First first = second;
Console.WriteLine(first.GetName());
// Prints "First"
Console.ReadKey();
}
}
你会发现它两次都是第二次打印。为什么要在抽象方法声明中使用
new
关键字?此外,你不能重写C中的方法,除非它是虚拟的或抽象的Beverage.GetDescription()
两者都不是。我找不到解释得更清楚的帖子,但我认为这与您选择左侧的Beverage
类型有关,因此调用beverage2.GetDescription()
只调用基类方法。您可能必须强制转换它,Console.WriteLine(((Mocha)beverage2.GetDescription())
为什么要在抽象方法声明中使用new
关键字?此外,不能重写C中的方法,除非它是virtual
或abstract
Beverage.GetDescription()
两者都不是。我找不到解释得更清楚的帖子,但我认为这与您选择左侧的Beverage
类型有关,因此调用beverage2.GetDescription()
只调用基类方法。您可能必须强制转换它,Console.WriteLine(((Mocha)beverage2.GetDescription())代码>谢谢Karle,Kai和觉醒字节,所有答案都非常有用。你的例子特别有用,Karle,谢谢!谢谢Karle,Kai和觉醒字节,所有答案都非常有用。你的例子特别有用,Karle,谢谢!