Search code examples
c++constantsbase-class

Hiding member variables that should not be mutated in a base class which only allows const access so one can keep the assignment operator


I have a member variable that should never be changed from inside the class it's in, so it should be const, but I'd like to keep the assignment operator for that class.

So I came up with the idea to "hide" the member in a base class that only allows const access trough a getter:

class Base
{
public:

    Base(Settings settings) : mSettings(settings) {}

    const Settings&
    GetSettings() const { return mSettings; }

private:

    Settings mSettings;
};

class Derived : Base
{
public:

    Derived(Settings settings) : Base(settings) {}
 };

I can access the member trough the getter, can't accidentally change it and it seems better then a simple wrapper because a wrapper could still be overwritten trough it's own assignment operator.

Anyone see any problems or pitfalls with this? Any backdoor ways to modify the member anyway that would render the whole construct useless?

EDIT: To give a little more context about the use case. The Settings are for a Product class. It includes things like the dimensions of the product. A product cannot resize itself, and I want to prevent accidentally doing so by somehow restricting access to the settings as const. However, it's fine for client code to make assignments x = y //Product x now has the same properties as y


Solution

  • Technically, you could still write:

    void oops(Settings s) {*dynamic_cast<Base*>(this) = Base(s);}
    

    But, honestly, good program design and good programming practices come side-by-side. I think you are safe enough: If someone goes this far to break your interface, there's something wrong with the programmers you're hiring. Access modifiers such as private and protected are not meant as a security feature: They are there to help you, a good developerTM, to avoid shooting yourself on the foot, and they do that by giving more information to the compiler (and yourself) on who is supposed to be accessing what information, so it can generate helpful error messages that are intended to prevent such errors.

    In short: You're the boss here, and not the compiler. Express your intent clearly (as you have done already) and don't try to use interfaces in a way that they are obviously not meant to be used, and you'll be fine.