3

Similar to the @property tag in python, I am trying to figure out if it is possible to override the behavior of a getter in c++ without having to make a function call.

Basically, is it possible to do the following in c++:

class vector2(class):
    def __init__(self):
        self.values = [1,2]

    @property
    def x(self):
        return self.values[0]
pos = vector2()
my_var = pos.x

Is the best solution to just write getters and setters?

  • 1
    You can fake it with implicit conversion, but IMO it's not worth it. Has corner cases, and can inhibit optimization. It's better to use idiomatic C++, which is just to use methods directly: https://stackoverflow.com/questions/8368512/does-c11-have-c-style-properties . MSVC _does_ have a nonstandard `declspec` extension for dynamic properties, but it's not supported by g++. clang supports it behind a flag. – parktomatomi Jan 10 '20 at 00:02
  • For that example in particular, you would overload `operator[]` but in general, this is not possible in C++ – Indiana Kernick Jan 10 '20 at 00:08
  • The C++ way is getters and setters. `int get_x() const { return values[0]; }` and `void set_x(int value) { values[0] = value; }` – Eljay Jan 10 '20 at 00:22
  • For going the other way array, overloading the `[]`, this answer is pretty cool - use a `constexpr` array of pointer-to-members and do a lookup. Optimizes down pretty close to what an inlined getter method would do: https://stackoverflow.com/a/48464023/1863938 – parktomatomi Jan 10 '20 at 00:30
  • Please review "Tell, Don't ask" articles. getters and setters simply waste your time - so simply put the code that uses the instance data in the object. – 2785528 Jan 10 '20 at 00:57
  • @parktomatomi I checked and a switch is better. https://godbolt.org/z/KrdzSK – Indiana Kernick Jan 10 '20 at 00:59

1 Answers1

2

The short answer is no, you can't do that.


For a 2D vector that you can access as an array, I would do something like this:

struct Vec2 {
  float x;
  float y;

  const float &operator[](const size_t i) const {
    static_assert(sizeof(Vec2) == 2 * sizeof(float));
    assert(i < 2);
    return (&x)[i];
  }

  float &operator[](const size_t i) {
    return const_cast<float &>(std::as_const(*this)[i]);
  }
};

So you can access the member variables directly or use the overloaded subscript operator.

Vec2 v{4, 5};
v.x += 9;
v[1] = -3;

In general, getters and setters are called explicitly. A naming convention I've seen quite a lot of is giving the getter and setter the same name.

class Foo {
public:
  int member() const {
    return hidden;
  }

  void member(const int value) {
    hidden = value;
  }

private:
  int hidden;
};

This naming convention makes access very clean but still makes it clear that a function call is taking place.

Foo f;
f.member(5);
int five = f.member();
Indiana Kernick
  • 5,041
  • 2
  • 20
  • 50