22

我想要一个具有常量字段的基类(例如与在编译后无法修改的类关联的唯一 ID)。到目前为止,static const声明会很好。现在,我想继承这个基类,并确保这个类的子类确实有相同的字段,但有自己的值。我怎样才能做到这一点?

比方说,我想要一个基类Base,其ID字段的int值为 0。然后,我想要类和A,它们都是我想要的公共子类确保这些孩子也将具有各自值为 1、2 和 3 的字段(通过“确保”,我的意思是如果他们没有明确声明的 ID,则会出现编译器错误)。BCBaseID

如果我能设法构建这个场景,我的期望是请求指针的ID字段,我应该得到不同的值,Base*具体取决于指针是创建为new A()还是。new B()new C()

我的猜测是声明IDvirtual static const,这当然没有意义并给出编译器错误。

但是,我该怎么做才能达到所描述的结果呢?(我唯一能想到的就是声明ID为一个返回整数的虚函数,然后将值硬编码到函数体中,但我正在寻找更优雅的东西。)

先感谢您!

4

2 回答 2

21

方法static不能virtual,数据成员也不能virtual

但是您可以隐藏static派生类中的字段并使用virtual方法返回它们。

class A
{
public:
    static const int ID = 0;
    virtual int getID() { return A::ID; }
};
class B : A
{
public:
    static const int ID = 1;
    virtual int getID() { return B::ID; }
};

选择:

class A
{
public:
    A(int id = 0) : ID(id) {}
    const int ID;
    getID() { return ID; }
};
class B : public A
{
public:
    B() : A(1) {}
};
于 2012-06-06T13:52:52.050 回答
0

在 C++ 中拥有虚拟静态成员确实非常有用。它们可以很容易地添加到语言中,不需要新的关键字。以下代码示例为图形库命名形状类型:

class Shape {
public:
    static constinit virtual std::string name = delete;
    static constexpr virtual bool closed = delete;
    ...
};

class Circle : public Shape {
public:
    static constinit std::string name override { "circle" };
    static constexpr bool close override { true };
    ...
};

class Line : public Shape {
public:
    static constinit std::string name override { "line" };
    static constexpr bool close override { false };
    ...
};

这声明Shape为抽象基类,Shape::nameShape::closed通过= delete.

虚拟静态成员的空间可以分配在同一个 VTable 中,该 VTable 已经用于虚拟函数调用。如果所有虚拟静态成员都是constinit(C++20 中的新成员)或constexpr,则 VTable 可以写入只读内存,目前大多数编译器也将其写入其中。如果不是,则必须将 VTable 放置在读写内存中。

一般来说,虚拟静态成员不需要是const,它们也可以是读写的。

虚拟静态成员既可以使用类名作为前缀访问(它们的行为与普通静态成员一样),也可以通过对象访问,其中对象的 VTable 指针将用于访问正确的 VTable。

只要它们不在标准中,就可以使用虚函数来模拟它们,它返回对局部静态变量的引用:

virtual const std::string& get_name() const {
    static const std::string name { "circle" };
    return name;
}

如果派生类不覆盖静态成员(分别是虚拟 getter 函数),则真正的虚拟静态成员和模拟的虚拟静态成员之间的语义有点不同:父类和子类之间的真正虚拟静态成员实际上会引用该对象的不同实例,并为父级和每个子级调用构造函数,它不会覆盖虚拟静态成员。但是模拟的 getter 函数总是会返回对完全相同的对象的引用。在只读虚拟静态成员上,这不应该产生影响(除非构造函数实际上以不同方式初始化每个实例),但在读写虚拟静态成员上,更新它们会产生影响。

于 2020-10-20T18:42:24.930 回答