初始化派生类虚拟函数返回的内联静态变量的最佳方法。

问题描述 投票:0回答:1

最初我把m_damage作为基类Projectile中的一个类成员,在每个派生类的初始化列表中赋值,并在基类中设置一个getter函数。

但后来我意识到我不需要每个派生类的实例都持有一个m_damage的副本,因为它对每个派生类的所有实例都是相同的值,所以我需要让这个值成为 static 并让每个派生类以 virtual 函数覆盖。

经过网上和这里的研究,我相信 inline static const 变量是最好的方法。但是把它作为类成员或类常量有什么好处吗,还是有其他更好的方法?我只想通过projectile中的私有虚拟函数来访问这个值。

Projectile.h文件

class Projectile
{
private:
    virtual int getDamage() const = 0;
}

火箭.h文件

class Rocket : public Projectile
{
private:
// inline static const auto ROCKET_DAMAGE = 400;  <---- make it a class member?
    virtual int getDamage() const final override;
}

火箭队

// inline static const auto ROCKET_DAMAGE = 400;  <---- make it a class constant?

int Rocket::getDamage() const
{
    return ROCKET_DAMAGE;
}
c++ inheritance virtual-functions static-variables
1个回答
1
投票

从API设计的角度来看,一个常量是一个实现细节。因此,你可能想把这个实现细节--即常量--隐藏在成员函数的定义后面,在基类的 .cpp 文件,因为你已经有了。

rocket.hpp:

class Rocket: public Projectile {
private:
    virtual int getDamage() const final override;
};

rocket.cpp:

static constexpr auto ROCKET_DAMAGE = 400; // not exposed to client

int Rocket::getDamage() const {
    return ROCKET_DAMAGE;
}

注意到有了常数 ROCKET_DAMAGE 作为数据成员,就像下面的例子一样,将其暴露给客户端。

class Rocket: public Projectile {
private:
   inline static const auto ROCKET_DAMAGE = 400;
};

常量可以被编译到客户端的代码中。这意味着每次改变常量的值时,客户端的代码都需要重新编译。ROCKET_DAMAGE.

相反,如果常数 ROCKET_DAMAGE 不会通过头文件暴露给客户端,因为它被隐藏在了 .cpp 文件(如前一种情况),改变常量的值不可能需要重新编译客户端代码。


1
投票

这是静态类变量的一个很好的用例。如果是常量,对类的所有对象都是一样的值,如果是数据成员,只会浪费内存。我会继续把它也变成 constexpr 所以它在编译时就被分配了,如果你需要的话,它可以用于编译时的计算(假设你有一个支持C++17的编译器}。

constexpr static auto ROCKET_DAMAGE = 400;

解决这个问题的另一种方法是不使用静态变量,而是直接从虚拟函数中返回值。

int Rocket::getDamage() const
{
    return 400;
}

使用静态类变量会使你在将来需要改变值时稍微容易一些:直接修改头文件就可以了,而不是在实现文件中翻找正确的函数定义。然而,这可能是一个负面的因素,如果头文件是 #include-d在多个文件中,因为这将需要重新编译所有带这个头的源文件,这意味着更长的编译时间。

© www.soinside.com 2019 - 2024. All rights reserved.