0

My base class must provide an interface to get a value that is dependent solely on the type of the derived class. I can think of two ways of implementing this:

Solution A, virtual functions:

class Base
{
public:
    virtual ~Base() = default;

    virtual int get_plain_value() const = 0;
};

class A final: public Base
{
public:
    int get_plain_value() const override
    {
        return 42;
    }
};

class B final: public Base
{
public:
    int get_plain_value() const override
    {
        return 35;
    }
};

Solution B, variable on base class:

class Base
{
public:
    virtual ~Base() = 0;

    int get_plain_value() const
    {
        return plain_value;
    }

protected:
    int plain_value;
};

Base::~Base() {}


class A final: public Base
{
public:
    A()
    {
        plain_value = 42;
    }
};

class B final: public Base
{
public:
    B()
    {
        plain_value = 35;
    }
};

Solution A is more robust (i.e. base class can not "forget" to set the value), and uses less memory (I have one new entry in vtable, which is per class, instead of one new variable per object).

But solution B is faster and much simpler from compiler's perspective, so much that get_plain_value() is most likely inlined, and the value is simply read directly from the object memory, avoiding a function call entirely.

Is there a third option with benefits from both approaches? What is the recommended solution in these cases?

5
  • In solution B, you can enforce that the variable is provided by the base classes by deleting the default constructor and creating a base constructor.
    – amon
    Commented Jun 1, 2020 at 20:37
  • Whatever extra ways you could come up with, they will be lesser than the first way. From an OO perspective you should not put knowledge or anticipation about the usage or needs of derived classes in your base class. The variable approach is already leaning towards that and it won't get any better. Commented Jun 1, 2020 at 20:55
  • How about a meta-progamming approach. Define a free floating function, that is templated for each "implementation". eg: template <> int plain_value<A>() { return 42; }; template <> int plain_value<B>() { return 35; }. This will only work if the callers are themselves templated or dedicated to a specific implementation.
    – Kain0_0
    Commented Jun 2, 2020 at 7:29
  • What percentage of the running time of your application is spent in that function call in Solution A? That is how much of a performance difference you can make by optimizing there and I doubt it even reaches 1%. Commented Jun 2, 2020 at 12:04
  • Because of the enforcement solution A is better. About performance, profile then change if neeeded Commented Jun 2, 2020 at 15:24

1 Answer 1

3

You use what is more robust and less error prone. Should you be told that the performance of this particular function is important, and after you have profiled it, you can change it. I very very much doubt that it will be performance critical.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.