我是 C++ 新手,在 C/C#/Objective-C 等 OO 语言方面有多年经验。现在,我正在学习 C++。
我看到了这个 C++ 代码:
class World : public State
{
};
似乎类公开World
继承了该类。State
公共子类化?很难理解。
这个功能的概念是什么?这在什么时候有用或需要?
我是 C++ 新手,在 C/C#/Objective-C 等 OO 语言方面有多年经验。现在,我正在学习 C++。
我看到了这个 C++ 代码:
class World : public State
{
};
似乎类公开World
继承了该类。State
公共子类化?很难理解。
这个功能的概念是什么?这在什么时候有用或需要?
对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”关系,因为它看不到继承。
这是一个非常好的区别——如果有疑问,只需使用显式组合。引入继承来节省类型非常好,直到它产生一些意想不到的后果。
如果
class World: private State
{
};
私有继承意味着所有public
和protected
的成员State
将被继承World
并且将成为private
。这封印State
在里面World
。任何继承自的类World
都不能访问State
.
是什么让你认为它是私人的?它在那里说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。
祖先类名称前的 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
通常,您应该使用公共继承,因为继承不应仅用于实现重用(私有继承就是这样做的)。