2010-05-25 77 views
3

注意:这个问题是用类似于伪代码的C#编写的,但我真的会问哪些语言有解决方案。请不要挂上语法。有趣的铸造和继承

说我有两类:

class AngleLabel: CustomLabel 
{ 
    public bool Bold; // Just upping the visibility to public 
    // code to allow the label to be on an angle 
} 

class Label: CustomLabel 
{ 
    public bool Bold; // Just upping the visibility to public 
    // Code for a normal label 
    // Maybe has code not in an AngleLabel (align for example). 
} 

他们都从该类decend:

class CustomLabel 
{ 
    protected bool Bold; 
} 

大胆场暴露在后裔类公众。

这些类没有可用的接口。

现在,我有一个方法,我希望可以通过CustomLabel并设置Bold属性。这可以在不需要1)找出对象的真实类别并且2)投射到该对象然后3)为每个标签类型的每个变量分别设置粗体代码的情况下完成。有点像这样:

public void SetBold(customLabel: CustomLabel) 
{ 
    AngleLabel angleLabel; 
    NormalLabel normalLabel; 


    if (angleLabel is AngleLabel) 
    { 
     angleLabel= customLabel as AngleLabel 
     angleLabel.Bold = true; 
    } 

    if (label is Label) 
    { 
     normalLabel = customLabel as Label 
     normalLabel .Bold = true; 
    } 
} 

这将是很好,也许做一个演员,然后在一个变量上设置粗体。

我在想什么是做第四课,只是公开大胆的变量,并将我的自定义标签投给该类。

会这样吗?

如果是这样,它将使用哪种语言? (这个例子是从Delphi的旧版本(德尔福5)中提取的)。我不知道它是否适用于该语言,(我仍然需要尝试一下),但我很好奇它是否适用于C++,C#或Java。

如果没有,有什么想法会有效吗? (请记住没有提供接口,我不能修改类。)

任何人都有猜测?

+0

你为什么要这么做? – alternative 2010-05-25 21:25:58

+0

'AngleLabel'和'Label'不能控制''粗体'标志吗?为什么他们必须拥有自己的? (如果'Control.bold'与问题无关,为什么要显示它?) – sbi 2010-05-25 21:27:22

+0

@sbi - 对于混淆,我会删除控件引用。正如我所说,这个例子是从Delphi中提取的。 Delphi中的控件类没有大胆的属性。 – Vaccano 2010-05-25 21:30:24

回答

7

这将在德尔福工作。与其使用的类相同的单元中的代码具有对受保护(但不是严格受保护)成员的隐式访问,即使是在另一个单元中声明的成员也是如此。 You'de申报财产保护在CustomLabel

type 
    CustomLabel = class 
    private 
    FBold: Boolean; 
    protected 
    property Bold: Boolean read FBold write FBold; 
    end; 

大胆的设定程序,在另一个单元,将有自己的CustomLabel后裔:

type 
    TAccessCustomLabel = class(CustomLabel); 

procedure SetBold(customLabel: CustomLabel) 
begin 
    TAccessCustomLabel(customLabel).Bold := True; 
end; 

不能使用as上投因为实际参数永远不会是TAccessLabel的一个实例。这将是AngleLabelNormalLabel的一个实例,但由于所有三个类从CustomLabel继承的部分是共同的,因此Bold属性在所有这三个类中都是相同的。这仍然是真实的,即使后财产已经公布或出版的后裔:

type 
    AngleLabel = class(CustomLabel) 
    public 
    property Bold; 
    end; 

您可以更改属性的可见性,而不是场。如果您尝试使用同一个字段,则会声明一个新的字段,其​​中隐藏了继承的字段。


你可以在C++类似的东西,但它并不像通常做法,因为它是在Delphi中,所以它很可能得出一些愤怒,特别是如果你打算编写可移植代码。

声明第四个类,就像在Delphi中一样。 C++并不像Delphi那样随会员访问一样松散,但它具有友谊的概念,在这种情况下它的工作原理也是如此。

class AccessCustomLabel: public CustomLabel 
{ 
    friend void SetLabel(CustomLabel* customLabel); 
}; 

那现在的功能已经完全进入该类的成员:

void SetLabel(CustomLabel* customLabel) 
{ 
    // Not allowed: 
    // customLabel->bold = true 

    // Not ordinarily allowed; requires friendship 
    reinterpret_cast<AccessCustomLabel*>(customLabel)->bold = true; 
} 

这是技术上未定义的行为因为我们型铸造对象的类型,它并没有真正有。我们依靠CustomLabel的所有后代拥有相同的布局,特别是的bold成员与任何其他CustomLabel子孙的bold成员位于相同的相对位置。


在Delphi和C类型铸造++代码执行型双关。你不会在C#或Java中脱身;他们检查他们的演员的结果,所以如果customLabel并不真的持有AccessCustomLabel的实例,你会得到一个例外。您必须使用反射才能访问这些语言中不相关类的受保护成员。证明这超出了我的深度。

+0

事实上,他们是属性,所以这应该很好。我会试一试。谢谢。 – Vaccano 2010-05-25 21:48:23

0

你可以做的是在CustomLabel和其他两个类之间添加一个中间类(例如命名为CCC)。

public class CCC : CustomLabel 

该类应该有一个名为SetBold(bool bold)的函数来设置受保护的字段。

public void SetBold(bool bold) 
{ 
    base.Bold = bold; 
} 

AngleLabel和标签都将继承CCC

和参考setBold(...)的参数将是类型CCC

+0

唉,正如我提到我的问题结束。我无法更改AngleLabel或Label类。 – Vaccano 2010-05-25 21:31:32

3

的。由于父母被保护的答案是,它不应该工作在没有额外工作的情况下使用任何语言,除非有问题的代码是在自定义版本的后代中执行的。

德尔福有一个选项使用protected hack使其工作。 C#和Java可以使用反射。 C++的朋友可以用来使它工作。

但是,如果您在CustomLabel中声明了Bold为Public,那么该功能将适用于您指定的所有语言。 Delphi,C++,C#和Java,而不必做任何特殊的事情。

1

C++将与模板解决这个问题(假设SetBoldBold你的样品中的等价物):

template<typename T> void SetBold(T t) { 
    t.SetBold(); 
} 
+1

这在给定的用例中不起作用。在C++语法中,输入参数是“CustomLabel * customLabel”。模板执行编译时多态性,但要做到这一点,您需要知道编译时的实际类型,这意味着您无法转义检查“CustomLabel”的每个已知后裔并访问特定于类的'Bold'的代码。会员。模板可以让你逃避为每个单独的类实现'SetBold',但它不会帮助调度。 – 2010-05-25 21:49:02

1

如果您使用的是Delphi 2005或更高版本,则可以使用类助手。类助手可以访问“帮助”类的受保护字段和方法。C#扩展方法可能类似,但这不是我熟悉的领域。

注意:由于我没有编译器,所以我一直无法测试。

type 
    TLabelHelper = class helper for CustomLabel 
    public 
    procedure SetBolded(ABold : Boolean); 
    end; 

procedure TLabelHelper.SetBolded(ABold : Boolean); 
begin 
    Bold := ABold; 
end; 

...

Label.SetBolded(True); 
1

在C#3.0和更高版本可以使用extension methods;这些与Gerry提到的Delphi Class Helpers类似。

它沿着这些线(观看关键字this)。

public static class CustomLabelExtensions // name here is not important, just make it readable 
{ 
    public static void SetBolded(this CustomLabel customLabel, bool newValue) 
    { 
     customLabel.Bold = newValue; 
    } 
} 

注意我忘了命名空间,就像你在伪代码中做的一样。
请确保CustomLabelExtensions对于您的代码是可见的,无论是通过使用它的'名称空间还是通过显式指定该名称空间。

另请注意,扩展方法只允许您添加方法,而不是属性(来自Delphi背景,这对我来说很奇怪)。

然后你使用上面的代码是这样的:

AngleLabel angleLabel; 
NormalLabel normalLabel; 
// some code that assigns values to the variables 
angleLabel.SetBolded(true); 
normalLabel.SetBolded(true); 

--jeroen