内存中的继承保护成员变量副本

Inheritance protected members variables copies in memory

有人告诉我,如果我在基 class 包含受保护的成员变量时进行继承,并且子 class 将构造基 class,它将在内存中复制它的成员.示例:

class Animal
{
public:
    virtual std::string& sound() { return m_sound; }
    virtual void setSound(std::string& sound) { m_sound = sound; }
    virtual int age() { return m_age; }
    virtual void setAge(int age) { m_age = age; }
protected:
    Animal(std::string sound, int age) : m_sound(sound), m_age(age) { }

    int m_age;
    std::string m_sound;
};

class Dog : public Animal
{
public:
    Dog(int speed) : Animal("Waff!!", 3), m_speed(speed) {}
    virtual int speed() { return m_speed; }
    virtual void setSpeed(int speed) { m_speed = speed; }
protected:
    int m_speed;
};

所以使用上面的例子,换句话说,如果我创建一个 Dog 对象,它将为 m_sound 和 m_age 分配 2 倍的内存。
这对我来说完全没有任何意义,我一直想知道为什么编译器会做这样的事情,除非我听到的信息具有误导性。
所以说我们主要创建:

Dog bulldog(5);

调试这段代码并查看这里的内存是我得到的:

我想知道在父 class 数据和子数据之间的问号所在的内存区域中究竟分配了什么。

I got told that if i do inheritance when the base class contains protected member variables and a child class will construct the base class, it will duplicate it's members in memory. ... it'll allocate 2 times memory for m_sound and m_age.

没有。在您的示例中,每个 Dog 类型的对象只包含两个 int 的子对象和一个 std::string 类型的子对象。技术上允许编译器使用比必要更多的存储空间,但没有理由这样做,并且不允许程序对同一成员或多个 std::string 构造函数或析构函数调用具有不同的地址。

在不知道你的消息来源的情况下,没有太多要说的了。

What exactly gets allocated in memory where the questions marks between the parent class data and the child?

详细信息取决于您的编译器和标准库,但很可能您标识为 m_agem_speed 之间的全部或大部分字节属于 std::string m_sound 成员子对象.也就是说,我猜如果你这样做 std::cout << sizeof(std::string) << "\n";,你会得到 28 或接近它。

由于 C++ 对象模型的工作方式,sizeof(std::string) 是一个常量,每个 std::string 只能得到固定数量的字节,但一个字符串可以 "contain" 许多字符.这通常意味着 std::string 有一个 char* 指向动态分配内存的指针,该内存包含实际字符。它通常还需要一种方法来了解字符串的长度和动态分配的缓冲区的容量。

但是正如您所注意到的,字符串的字符值实际上直接出现在 std::string 对象的内存中,这可能意味着您的标准库实现正在使用 Small String Optimization: a std::string 可以包含一个 char* 指针和长度和容量,或者直接包含一定数量的字符值。 (这可以减少动态分配和释放内存的需要,如果经常使用,这可能会花费很多 CPU 时间。)std::string 还需要一些方法来了解它当前是否处于指针模式或直接存储模式,并且该信息大概位于后面的字节中。

要准确解读 std::string 中每个字节的含义,您需要在编译器使用的头文件中查找 class 模板 std::basic_string 的定义。