抽象基类中初始化const成员变量的常用解决方案

Posted

技术标签:

【中文标题】抽象基类中初始化const成员变量的常用解决方案【英文标题】:Common solution for initializing const member variable in abstract base class 【发布时间】:2020-09-26 15:06:15 【问题描述】:

鉴于以下情况

class Base

public:
    Base(double par1, double par2)
        :
        par1_(par1),
        par2_(par2)
        

    const double value_;

protected:
    const double par1_, par2_;
    virtual double Calc_Value() = 0;
;


class Derived_A : public Base

public:
    Derived_A(double par1, double par2)
        :
        Base(par1, par2)
        
  
protected:
    double Calc_Value()
        
            // <code to calc value with par1_ and par2_>
        
;


class Derived_B : public Base

public:
    Derived_B(double par1, double par2, double par3)
        :
        Base(par1, par2),
        par3_(par3)
        

    const double par3_;

protected:
    double Calc_Value()
        
            // <code to calc value with par1_, par2_ and par3_>
        
;

int main()

    std::vector<Base*> my_vector;
    // do stuff using polymorphism

这一直困扰着我一段时间。在创建Derived_ADerived_B 的对象时,我想用Calc_Value() 初始化value_。我知道只有Base 可以初始化它的 const 成员。现在,我的类对象主要是某种容器,它们在创建时计算必要的值。所以它们应该是只读的。 我知道我可以使 value_ 不是 const,但这会使它变得可变。我在互联网上找到的大多数解决方案只是在Base 中创建一个额外的构造函数,但是我必须在基类中声明par3_,这意味着,每次有一个derived_A 对象时,它都会有一个@987654331 @ 成员变量,而从未使用过它。另外,假设我想要更多具有不同Calc_Value() 函数的派生类,那么我是否需要为每个额外的子类声明一个构造函数?到目前为止,我已经通过将Calc_Value() 函数设为public 解决了这个问题,因此不需要public const 成员变量。但是在通过函数访问对象时,我认为圆括号会降低可读性,这就是为什么我希望在Base 中有一个 const 成员变量。

这个问题有通用的解决方案吗?

【问题讨论】:

如果是const,则必须在构造函数初始化列表中进行初始化。 如果value_的值只有派生类知道,为什么它是基类的成员?例如,您可以在 Base 中有一个纯虚拟 getValue 函数,并让派生类提供值。 请注意,要正确使用多态性,您需要在基类中定义一个虚拟析构函数。 @super value_ of base 需要包含计算值,否则myvector[idx]-&gt;value_ 将不起作用或您的意思是什么?另外,您的意思是像Calc_Value() 这样的纯虚函数,但是是公开的?我这样做了,但我认为圆括号会降低可读性,这就是为什么我想要一个 const 成员。我只是想知道是否有我不知道的解决方案。我不是经验丰富的程序员 @anastaciu 感谢 cmets!我想,我想做的事情是不可能的。是的,我忘记了示例中的析构函数。 【参考方案1】:

您可以在您的基类中有一个const double&amp;,并将双精度值存储在您的派生类中。像这样。

#include <iostream>

struct Foo 
    Foo(const double& ref) : value(ref) 
    const double& value;
;

struct Bar : Foo 
    Bar(const double p1, const double p2) : Foo (value), value(p1 + p2) 

    private:
    double value;
;

int main() 
    Bar b(5, 3);

    Foo* f = &b;

    std::cout << f->value;

这里Bar 允许修改value,但由于Base 有一个const ref,你不能使用引用修改值。

如果您还需要将Bar::value 设为const,则需要在构造函数初始化程序列表中对其进行初始化。如果您还需要一个函数来计算该值,则它不能是成员函数,因为在构造对象之前您不能调用成员函数。

在这种情况下,您可以将Calc_value 设为静态成员函数,并从Bar 的构造函数传递它所需的参数

struct Bar : Foo 
    Bar(const double p1, const double p2) : Foo (value), value(Calc_value(p1, p2)) 

    private:
    static double Calc_value(const double p1, const double p2) 
        return p1 + p2;
    
    double value;
;

看起来你只是为了避免此时写()而让你的代码有点过于复杂。

【讨论】:

以上是关于抽象基类中初始化const成员变量的常用解决方案的主要内容,如果未能解决你的问题,请参考以下文章

具有数据成员的抽象基类

C++ const修饰类成员的说明

可以通过[重复]在派生类中初始化受保护的基类成员

const成员变量

转C++ const成员变量和成员函数(常成员函数)

C/C++类和对象类中常用的关键字总结