18

我是 C++ 新手,在 C/C#/Objective-C 等 OO 语言方面有多年经验。现在,我正在学习 C++。

我看到了这个 C++ 代码:

    class World : public State
    {
    };

似乎类公开World继承了该类。State公共子类化?很难理解。

这个功能的概念是什么?这在什么时候有用或需要?

4

4 回答 4

21

public关键字的需求只是对于使用关键字定义的类class,默认访问修饰符(对于所有内容 - 数据成员、成员函数和基类)是private. 所以

class World : State {};

是相同的:

class World : private State {};

这可能不是你想要的——这意味着基类只能在类中访问World。外人“根本不知道”遗产的存在。

对于用关键字定义的类struct,默认的访问修饰符是public,所以你可以这样写:

struct World : State {};

并得到一些看起来和行为有点像其他所有继承语言的东西。但是struct关键字,以及它定义一个类的事实,实际上只是为了与 C 兼容。你不会找到很多 C++ 风格指南推荐使用它只是为了获得默认的公共可访问性 - 通常它只用于是 POD 的类,或者可能仅适用于根本没有成员函数的类。

至于为什么 C++ 首先有私有继承:对于大多数用途来说,私有继承是一种组合形式。正常组成:

class World {
    State state;
  public:
    void foo() {
        state.bar();
        state.baz();
        and so on
    }
};

即 World 类知道它是使用 State 实现的,而外界不知道 World 是如何实现的。

对比

class World : private State {
  public:
    void foo() {
        bar();
        baz();
        and so on
    }
};

也就是 World 类知道它是通过作为State 来实现的,而外界不知道它是如何实现的。using State::bar;但是您可以通过例如放入World 定义的公共部分来选择性地公开部分 State 接口。效果就像您在 World 中费力地编写了一个函数(或几个重载),每个函数都委托给 State 上的相同函数。

但是,除了避免键入之外,私有继承的一种常见用途是当类State为空时,即没有数据成员。然后,如果它是它的成员,World则它必须占用一些空间(诚然,根据对象布局,这可能是否则只是填充的空间,因此它不一定会增加 的大小World),但如果它是基类,那么称为“空基类优化”的东西开始起作用,它可以是零大小。如果您要创建很多对象,这可能很重要。私有继承启用优化,但外部世界不会推断“is-a”关系,因为它看不到继承。

这是一个非常好的区别——如果有疑问,只需使用显式组合。引入继承来节省类型非常好,直到它产生一些意想不到的后果。

于 2011-01-22T15:03:54.020 回答
7

如果

class World: private State
{
};

私有继承意味着所有publicprotected的成员State将被继承World并且将成为private。这封印State在里面World。任何继承自的类World都不能访问State.

于 2011-01-22T15:04:07.883 回答
3

是什么让你认为它是私人的?它在那里说public,这意味着它是公开的子类化。

除此之外,私有继承和受保护继承的作用与公共继承相同,只是所有成员变量都是函数,至少具有私有或受保护的可访问性。例如,如果State有一个公共成员函数 'foo()',它将在 'World' 中是私有的。

这在实践中很少使用,但它确实有目的。我见过的最常见的用法是通过继承进行组合。即,您想要“具有”关系而不是“是”(通常通过公共继承获得)。通过私有继承该类,您可以获得它的所有变量和方法,但您不会将它们暴露给外界。

使用私有继承进行组合的优势之一来自空基类优化 (EBCO)。使用普通组合,拥有一个空类的成员对象仍将使用至少 1 个字节,因为所有变量都必须具有唯一的地址。如果你私下继承了你想要组成的对象,那么这不适用,你也不会遭受记忆损失。

例如

class Empty { };

class Foo
{
    int foo;
    Empty e;
};

class Bar : private Empty
{
    int foo;
};

在这里,sizeof(Foo)可能是 5,但sizeof(Bar)由于基类为空,所以会是 4。

于 2011-01-22T15:03:02.473 回答
1

祖先类名称前的 public/protected/private 关键字表示来自祖先的成员所需的可见性。使用私有继承,后代只从祖先那里继承实现,而不是接口。

class A {
public:
  void foo();
};

class B : private A {
public:
  void bar();
};

void B::bar()
{
  foo();  // can access foo()
}

B b;
b.foo(); // forbidden
b.bar(); // allowed

通常,您应该使用公共继承,因为继承不应仅用于实现重用(私有继承就是这样做的)。

于 2011-01-22T15:06:04.580 回答