派生类中的私有虚函数重写

4
如果基类中的虚成员函数是公有的,那么将其覆盖并私有化是否有意义?
struct base {
    virtual void a();
};

struct derived : base {
// ...
private:
    void a() override;
};
4个回答

1

是的,如果您将基类继承为私有,则会出现这种情况。否则,它更像是一种奇怪的显式限制——用户必须进行显式转换才能使用该函数——通常不建议这样做,因为很少有人能理解作者的意图。

如果您想要限制一些来自基类的函数,请进行私有/保护继承,并通过using关键字在派生类中声明您希望受保护/公共的基础方法。


1
如果你被迫在实现类上进行两阶段构造(即必须调用一个init()方法或者代替一个构造函数(我知道,但是有原因),那么这会阻止你在将其作为接口指针传回之前直接调用实例指针上的任何其他方法。走一步更远,将继承设为私有,并让您的一个公共init函数返回接口指针!另一个原因是你根本不需要在最终实现类声明中编写public:,所以默认情况下所有内容都是私有的。但是,为什么要这样做并使用结构体而不是类,我不知道。也许由于风格战争,这是从类转换过来的?

1
除了默认访问权限之外,classstruct之间没有任何区别。 - 463035818_is_not_a_number
@formerlyknownas_463035818确实如此。因此,如果您有一个实现类,它可以全部默认为private,因为没有任何方法会被直接调用。然后某些风格战士会出现并说:“这应该是一个结构体,因为'blah是wotsit'”,这个规则在那个圈子之外毫无意义,初级程序员将其更改为结构体(因为风格战士只有在真正惹恼原始作者时才会自己更改东西),并放入private:,以便它的行为相同,因为没有人想重新测试它。然后你就有了OP代码。 - Gem Taylor
我宁愿编写一个总是返回完全初始化对象的工厂,也不想这样做。如果需要,您可以使用标签类来允许仅工厂创建对象。 - Jens

1

看到你的设计,我发现不能直接调用derived::a,只能通过base接口。

这有什么意义吗?考虑一下,一旦我们有了一个derived实例,我们总是可以向上转型为其基类,所以给定

derived d;

虽然 d.a() 无法编译,但我们总是可以这样做:

base & b = d;
b.a(); //which actually calls derived::a

换句话说:derived::a 并不是那么私有,我不建议使用这种设计,因为它可能会使用户感到困惑,但需要注意的是保留了 html 标签。
如果 derived 中的成员在 base 中也是私有的,则情况会有所改变:这时很明显它们不能直接在 base 或者 derived 之外被调用。
假设我们有一对函数,想要根据传递给第三个函数的参数值条件地调用它们。
struct base 
{
    void dosomething(bool x)
    {
        if(x)
        {
            do_this();
        }
        else
        {
            do_that();
        }
    }
private:
    virtual void do_this(){}
    virtual void do_that(){}
};

因此,派生类可能如下所示:

struct derived : base 
{
private:
    void do_this() override { }
    void do_that() override { }
};

除非其他类扩展了base本身,否则不能调用它们:

derived d;
d.dosomething(true); //will call do_this() in derived
d.dosomething(false); //will call do_that() in derived

d.do_that() //won't compile

0
与非虚拟方法相同的推理适用:如果只有类本身应该调用它,则将其设置为私有。
考虑模板方法模式
struct base {
    void foo() { a() ; b(); }
    virtual void a() = 0;
    virtual void b() = 0;
};

struct derived : base {
private:
    void a() override {}
    void b() override {}
};
int main()
{
   derived().foo();
}

也许 ab 应该被声明为 protected,但无论如何,derived 可以改变访问权限,并且需要一些文档说明,以便 derived 知道应该如何实现 ab

为什么不在基类中将模板方法声明为私有的?这样可以表达这些方法是类内部使用的意图。 - Jens
@ Jens 我把那个当作前提。我必须承认我的例子并不太有说服力。 - 463035818_is_not_a_number

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