派生 class 可以小于其父 class 吗?

Can a derived class be smaller than its parent class?

我问的是关于 C++ 的问题,因为我对此很熟悉,但问题本身就很清楚:有没有一种语言可以让我们推导出 class 并使其占用更少 space 在记忆中比原来的class?

这个问题更像是一个噱头,而不是我试图解决的实际问题,但我可以想象一些真正高性能的代码可以从这种内存优化中受益:

假设我们有:

class Person {
    std::string name;
    unsigned int age;
}

class PersonNamedJared {
}

理论上,我们不需要此子class中的字段"name",因为它将始终是"Jared",这可以提高内存效率。

实现此目的的唯一方法是将 Person 中的 'name' 字段替换为 get_name() 函数,我们只需在 PersonNamedJared 中将其覆盖为始终 return"Jared"?我们如何在基数 class 中创建名称变量?

我知道这个例子是非常糟糕的做法,但这是我能想到的最好的做法。我认为实施这种模式是有正当理由的。

Can a derived class be smaller than its parent class?

没有。派生 class 始终包含基础 class 子对象。一个对象永远不能小于它的子对象,所以派生的 class 永远不能小于它的基础对象。

Is the only way to make this happen by replacing the 'name' field in Person with a get_name() function that we simply override in PersonNamedJared to always return "Jared"?

这将是实现它的一种方法。

How would we still make the name variable in the base class?

基类中不能有不想在派生类中出现的成员变量 class。

例如,您可以使用多重继承,以便在某些派生的 classes 中确实有一个带有变量的基数。像这样:

struct Person {
    unsigned int age;
    virtual std::string name() = 0;
    ...

struct Named {
    std::string name;
};

struct NamedPerson : Person, private Named {
    std::string name() override {
        return name;
    }
};

struct JaredPerson : Person {
    std::string name() override {
        return "Jared";
    }
};

这里有一个带变量的基数,但 Jared 没有继承那个特定的基数。

没有

继承自 class 意味着您包括它的所有成员变量,它是 parent class[s] 个成员变量,加上您自己的 class 包含的任何内容。

换句话说,child classes 是 parent classes 的超集。 (空 child class 除外)

即使私有成员仍然那里占用space,尝试访问它们只是一个编译器错误。

Can a derived class be smaller than its parent class?

在 C++ 中,不!

即使您尝试用派生 class 中的较小成员替换基 class 的成员(通过使用相同的名称),基 class 成员也是仍然存在(只是更难访问)。此代码将证明,派生的 class 实际上 添加 到基数的大小:

#include <iostream>

class A {
public:
    double q[200];
};

class B : A {
public:
    double q[100]; // Can we replace base array with a smaller one?
};

int main()
{
    std::cout << sizeof(A) << std::endl; // -> 1600 = 200 * sizeof(double)
    std::cout << sizeof(B) << std::endl; // -> 2400 ADDS 100 more doubles!
    return 0;
}

如果你使用多态性,答案应该很清楚。也就是说,利用允许您将派生类型的对象视为基本类型之一的语言功能。假设 PersonPersonNamedJared 的 public 基础并考虑以下代码。

PersonNamedJared Jared;
Person * Pointer = &Jared;
std::cout << Pointer->name << " is " << Pointer->age << " years old.";

这是有效的,但如果 PersonNamedJared 缺少 name 字段,此代码怎么可能工作?

根据经验,如果您有合理的理由希望派生 class 小于其基础 class,那么您的 [=32= 可能有问题] 设计。


关于有没有一种语言有这个特性,我觉得是有可能的,但是比较尴尬。您可以 - 在一种假设的语言中 - 通过允许标识符 name 表示基 class 中的(虚拟)数据但派生 class 中的函数来模糊数据成员和函数成员之间的界限es。因此派生的 class 可以提供一个名为 name 的函数,覆盖基础 class 版本。在处理派生类型的对象时,您可以阻止对 name 的基 class 版本的显式引用。如果有足够的要求和禁止,name 字段在某些派生的 class 对象中将无法访问,因此它们将不需要它。在这种情况下,名称字段可以省略。 (但是,我不知道有任何语言允许这种严格的设置。)

另一方面,这种设置感觉与继承的原则背道而驰。即使一种语言允许这种设置,我也更喜欢更好的 class 设计。