1
votes

Given the following situation

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
}

This has been bugging me for some time. I would like to initialize value_ with Calc_Value() when creating an object of Derived_A or Derived_B. I know that only Base can initialize its const members. Now, my class objects are mostly some sort of containers which calculate the necessary values when they are created. So they should be read only. I know I could make value_ not const, but that would make it mutable. Most solutions I found in the internet is just to create an additional constructor in Base but then I would have to declare par3_ in the base class which means, every time there is a derived_A object it will have a par3_ member variable without ever using it. Also, imagine I want to have more Derived classes with different Calc_Value() functions, do I then need to declare a constructor for every additional subclass? So far, I have overcome this problem with just making the Calc_Value() function public and therefore there was no need for a public const member variable. But when accessing the object via a function, the round brackets reduce readability in my opinion, which is why I would like to have a const member variable in Base.

Is there a common solution to this problem?

1
If it's const it must be initialized in the constructor initializer list.anastaciu
If the value of value_ is only known by the derived class, why is it a member of the base class? You could for example have a pure virtual getValue function in Base and let the derived class supply the value.super
Note that to correctly use polymorphism you need to define a virtual destructor in your base class.anastaciu
@super value_ of base needs to contain the calculated value, otherwise myvector[idx]->value_ won't work or what do you mean? Also, do you mean a pure virtual function like Calc_Value() but public? I did that but the round brackets reduce readability in my opinion which why I would like to have a const member. I was just wondering if there was a solution which I am not aware of. I am not an experienced coder.Andi
@anastaciu Thanks for the comments! I guess, what I wanted to do is not possible. And yes, I forgot the destructor in my example.Andi

1 Answers

1
votes

You could have a const double& in your base class and store the double in your derived class. Something like this.

#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;
}

Here Bar is allowed to modify value, but since Base has a const ref you can't modify the value using the reference.

If you need Bar::value to be const as well, you would need to initialize it in the constructor initializer list. If you additionally require a function to calculate that value it can't be a member function, since you can't call a member function before the object has been constructed.

In that case you could make Calc_value a static member function and pass it the parameters it needs from the constructor of 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;
};

It just seems like you are making you code a bit overly complicated just to avoid writing () at this point.