Search code examples
c++referencegetter-setter

Check C++ reference setter value


I have a question about the much-commented-about C++ reference getter-setter in C++. This is the base code:

class Foo
{
     X x_;
public:
          X & x()       { return x_; }
    const X & x() const { return x_; }
}

My issue with this is: what if I need to check the value when I set it? Let's imagine that I'm setting the latitude of a coordinate. If I were writing a setLat method, it would look like this:

void MyClass::setLat(double lat)
{
    if (lat < -90 || lat > 90)
    {
        throw std::range_error("The latitude must be between -90 and 90.");
    }
    _lat = lat;
}

Can I do something similar with:

double & MyClass::lat()
{
    return _lat;
}

Thanks

When I saw the code at the top of this question as the answer of another StackOverflow question, I thought, "Cool." But then, I ended up realizing what people here are saying: it breaks encapsulation. This member might just as well be public.

Since I don't use C++ that often, I wasn't too sure, thought.

The answer given by @ted-lyngmo did however make a lot of sense. I think that just having a regluar getter and a setter might in the end be the best. But I thought it might be possible to mimic the property ability of C# and Python in recent versions of C++. It looks like it is. Now: is it a good idea to do it? The question still seems open.


Solution

  • One option is to make a user-defined type of latitude and put all validations in that:

    class Latitude {
    public:
        Latitude() = default;
        
        explicit Latitude(double lat) : m_latitude(lat) {
            if (m_latitude < -90 || m_latitude > 90)
                throw std::range_error("The latitude must be between -90 and 90.");
        }
    
        explicit operator double() const { return m_latitude; }
    
    private:
        double m_latitude = 0.;
    };
    

    That way you could keep the class containing a latitude clean:

    class MyClass {
    public:
        void setLat(Latitude lat) {
            _lat = lat; 
        }
    
    private:
        Latitude _lat;
    };
    

    or

    class MyClass {
    public:
        Latitude& latitude() {
            return _lat;
        }
    
    private:
        Latitude _lat;
    };