在派生类中只暴露部分继承方法

4
我发现有一个关于OOPS的面试问题,问题如下: 有一个基类A有5个方法。现在如果一个类B继承自类A,那么只有3个方法会被公开。如果一个类C继承自类A,那么剩下的2个方法会被公开。 你有什么想法吗?

5
“不要那样做”是一道面试问题合适的回答吗? - adv12
2
@svinja 或许这就是正确的问题吧。你知道吗,有些人在面试中会问一些愚蠢的问题,只是为了看看候选人如何回答。 - Sriram Sakthivel
2
我认为这是一个有些玩弄文字的问题。你不应该维护类的层次结构,或许你只需要使用接口即可。 - hmnzr
将A公开或内部暴露给B,以使B无法调用A的2个方法。 - RadioSpace
2
new public void Foo() 是否算作“暴露” protected void Foo() - Alexei Levenkov
显示剩余7条评论
8个回答

4
如果A是部分的,并且您有2个命名空间,则:
namespace the_impossible
{
class Program
{
    static void Main(string[] args)
    {
        B b = new B();
        C c = new C();

        b.m1();
        b.m2();
        b.m3();

        c.m4();
        c.m5();
    }
}

namespace A_1
{
    public partial class A
    {
        public  void m1() { }
        public  void m2() { }
        public  void m3() { }
    }
}

namespace A_2
{
    public partial class A
    {
        public void m4() { }
        public void m5() { }
    }
}

class B : A_1.A 
{

}

class C : A_2.A
{ 

}
}

enter image description here enter image description here


3
在任何面向对象的语言中,都不应该出现这种情况,否则会违反Liskov替换原则。将B替换为A不应降低其正确性(意味着方法不应突然不可用)。
然而,问题仍然存在一些歧义,这允许一些“创新思维”。以下是我会向面试官提出的问题:
- “暴露”是什么意思? - A中的5个方法必须是公共的吗? - C的“暴露”是否需要是隐式的,还是可以明确地暴露(例如通过传递)?
根据这些答案,您可以使用internal、显式接口实现等来提出可能的选项。

谢谢你的回答。如果我们不使用继承,而是说呢?我有一个类A,其中包含5个或更多方法。我想向类A添加新方法,并将其专门提供给某些其他类(可能是通过继承或其他概念)。使用面向对象编程的概念,是否可以设计出这样的东西? - iJade
当然,你可以封装A并仅暴露你想要的内容,但这与继承非常不同。 - D Stanley
好的,我猜就是这样了。能否给个例子呢? :) - iJade

1
我所能想到的唯一方法是将它们全部设为 A 中的私有,然后通过 BC 的封装来暴露它们... 但它们没有被暴露,只是被执行了... 所以这只是半对的。

1
我认为这是一个欺骗或者愚蠢的问题。要实现这个,我们必须违反Liskov替换原则。你不应该保留类的层次结构。
也许你只需要使用接口代替:
public class A {} //why we even need this class?

public class B : A, I3Methods
{
    public void Method1() { }
    public void Method2() { }   
    public void Method3() { }
}

public class C : A, I2Methods
{
    public void Method4() { }
    public void Method5() { }
}

public interface I3Methods
{
    void Method1();
    void Method2();
    void Method3();
}

public interface I2Methods
{
    void Method4();
    void Method5();
}

0

我也认为这是不可能的。

但是,为了给出一个近似的答案:

在A中创建3个虚方法,然后在B中实现它们。接着在C中重写这2个方法。


这两个“隐藏”的A方法仍然会通过B暴露出来;它们只是没有被覆盖。 - D Stanley

0

我知道,回复已经晚了。只是想分享我的想法:

将类A定义为基类。 有中间子类A1 -> M1,M2,M3和A2 -> M4,M5从类A派生

现在,您可以有 1)类B继承A1 2)类C继承A2

这两个类仍然是从类A派生的。

而且我们也没有违反里氏替换原则。

希望这能给您带来清晰度。


0

没有人说在编写类A的时候必须公开5种方法。在C#中,您可以在类A中简单地编写5个受保护的方法,并通过编写一些带有new modifier的隐藏方法来公开那些您希望访问的方法 - 尽管这实际上不会直接公开方法,它们只是被包装起来了。

class A
{
    protected void M1() { }
    protected void M2() { }
    protected void M3() { }
    protected void M4() { }
    protected void M5() { }
}

class B : A
{
    public new void M1()
    {
        base.M1();
    }

    public new void M2()
    {
        base.M2();
    }

    public new void M3()
    {
        base.M3();
    }

}

class C : A
{
    public new void M4()
    {
        base.M4();
    }
    public new void M5()
    {
        base.M5();
    }
}

0
在你的评论中,你提到你是否有兴趣使用其他语言来完成这个任务。你可以通过使用 using 关键字,在 C++ 中实现类似的功能。因此,从类 A 开始:
class A {
public:
    int Method1() {     return 1;   }
    int Method2() {     return 2;   }
    int Method3() {     return 3;   }
    int Method4() {     return 4;   }
    int Method5() {     return 5;   }
};

然后你定义类B,使用私有继承(基本上你不能从B自动转换为A,并且A中的所有公共方法都变成了B中的私有方法)。

class B: private A {
public:
    // We want to expose methods 1,2,3 as public so change their accessibility
    // with the using keyword
    using A::Method1;
    using A::Method2;
    using A::Method3;

};

对于类C,同样暴露另外两个方法:

class C: private A {
public:
    using A::Method4;
    using A::Method5;

};

如果您需要通过 C 公开所有方法,只需使用公有继承即可,这样一切都存在:
class C: public A {
public:

};

使用方法:

B *b = new B();
b->Method1();  // This works, Method1 is public
b->Method4();  // This fails to compile, Method4 is inaccessible

我之所以说“有点”是因为你可以通过将B的实例显式转换为A来解决它:
A *brokena = b;  // This wouldn't compile because the typecast is inaccessible

A *a = (A*)b;    // This however does work because you're explicitly casting
a->Method4();    // And now you can call Method4 on b...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接