Thread: Class getter and setter functions help

  1. #1
    Registered User
    Join Date
    Jun 2009
    Posts
    8

    Class getter and setter functions help

    Hey all,
    I am searching the whole web for a good class getter and setter function tutorial but i cant seem to find any, i have lots of books but none of them talks about that...
    Can anyone help me find a book or a site that gives a good explanation on getter and setter function for classes.
    Thanks in advanced.

  2. #2
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    There isn't really much to it. Start by considering a non-class situation, a simple C approach using a global variable:

    Code:
    int
    	data = 0;
    	
    void set_data( int value )
    {
    	data = value;
    } 
    
    int get_data( void )
    {
    	return data;
    }
    That's the basic idea. Now let's say the data is a more complex type - an std::string, say. In that case, you should pass a const reference to the set function, and return a copy from the get function. And keep in mind that when dealing with classes, it's customary to declare the get function const, since the object isn't being changed in the process. If you don't, of course, you won't be able to call the function on a const object, or if the object has been passed as a const reference to a function.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  3. #3
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Quote Originally Posted by MasterM View Post
    Hey all,
    I am searching the whole web for a good class getter and setter function tutorial but i cant seem to find any,
    Good. They are usually a sign of a poor design, so you should avoid them.

  4. #4
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Good. They are usually a sign of a poor design, so you should avoid them.

    Not necessarily. It gives you better control (eg: you can filter or reject changes), and it allows the internal implementation to change without breaking existing code. It also make the interface more uniform, since you don't have to access data in the class in different ways. Personally, I prefer to use the same name for the get/set pair, but I know a lot of people don't like to do this, due to possible ambiguities.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  5. #5
    Student legit's Avatar
    Join Date
    Aug 2008
    Location
    UK -> Newcastle
    Posts
    156
    It's also a good idea to set your getter function as constant to make sure that it doesn't accidentally get changed by the rest of your program.

  6. #6
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    Quote Originally Posted by Sebastiani View Post
    >> Good. They are usually a sign of a poor design, so you should avoid them.

    Not necessarily. It gives you better control (eg: you can filter or reject changes), and it allows the internal implementation to change without breaking existing code. It also make the interface more uniform, since you don't have to access data in the class in different ways. Personally, I prefer to use the same name for the get/set pair, but I know a lot of people don't like to do this, due to possible ambiguities.
    I don't think he was proposing exposing member variables. Pure design says that a class should only expose operations. Getters and setters expose state, not operations.

    In my opinion, the real world doesn't work that way - getters are very often unavoidable, and even setters are needed from time to time.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

  7. #7
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> I don't think he was proposing exposing member variables. Pure design says that a class should only expose operations. Getters and setters expose state, not operations.

    Well, to be sure, he wasn't clear on that. Even so, to say that get/set functions are a sign of a poor design because they expose state is a moot point. All functions essentially get or set the state of something. But I do agree that "functions that expose unnecessary state information" should be avoided.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  8. #8
    The larch
    Join Date
    May 2006
    Posts
    3,573
    If you find doing something like

    Code:
    if (move_left) {
        enemy.set_x(enemy.get_x() + 1);
    }
    then perhaps the class is not exposing operations as it should. (Also, if state is complicated, providing lots of setters can make it hard to validate everywhere that conditions are met.)

    Another thing is naming:

    Code:
    class Enemy {
         bool alive;
         ...
         bool is_alive() const { return alive; }
         void kill() { alive = false; }
    };
    Would these members qualify as getter and setter?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  9. #9
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> then perhaps the class is not exposing *operations* as it should.

    Maybe, but I still don't see what the point is in making a distinction between *state* and *operations*. The terms are interchangeable, IMO.

    >> Another thing is naming: Would these members qualify as getter and setter?

    Why not? Personally, I would name the member variable 'alive_' and the get/set pair 'alive'. Accessing them then is a lot more like dealing with properties. Works for me, anyway.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  10. #10
    Registered User
    Join Date
    Apr 2008
    Posts
    890
    Quote Originally Posted by Sebastiani View Post
    >> I don't think he was proposing exposing member variables. Pure design says that a class should only expose operations. Getters and setters expose state, not operations.

    Well, to be sure, he wasn't clear on that. Even so, to say that get/set functions are a sign of a poor design because they expose state is a moot point. All functions essentially get or set the state of something. But I do agree that "functions that expose unnecessary state information" should be avoided.
    In general, classes should model behavior, structs should model data. Unfortunately, we see a lot of beginners who think classes are simply promoted structs with the appropriate getters and setters. So instead of ...

    Code:
    class Car {
    public:
        void drive();
    };
    ... we see ...

    Code:
    class Car {
    public:
         void setSteeringWheel (SteeringWheel sw);
         SteeringWheel getSteeringWheel();
         void setSparkPlug(SparkPlug sp);
         SparkPlug getSparkPlug();
         ...
    };
    Last edited by medievalelks; 06-16-2009 at 11:41 AM.

  11. #11
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> Unfortunately, we see a lot of beginners who think classes are simply promoted structs with the appropriate getters and setters.

    It doesn't really have anything to do with get/set functions (specifically), though. That is, *any* and *all* superfulous functions should be avoided.

    >> In general, classes should model behavior, structs should model data.

    Seems like an arbitrary distinction to me, anyway.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

  12. #12
    The larch
    Join Date
    May 2006
    Posts
    3,573
    Why not? Personally, I would name the member variable 'alive_' and the get/set pair 'alive'. Accessing them then is a lot more like dealing with properties. Works for me, anyway.
    And what if you want to change the implementation:

    Code:
    class Enemy
    {
        int health;
        ....
    
        bool alive() const { return health > 0; }
        void alive(bool a)
        {
            if (!a) {
                health = 0;
            }
            else {
                ????
            }
        }
    }
    My code had kill() but prevented resurrecting an enemy (well, one can always create another enemy).

    It's easier to control what can and cannot be done with a class if you keep the number of setters low.
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  13. #13
    Guest Sebastiani's Avatar
    Join Date
    Aug 2001
    Location
    Waterloo, Texas
    Posts
    5,708
    >> My code had kill() but prevented resurrecting an enemy (well, one can always create another enemy).

    OK, well, I hadn't thought that one through much.
    Code:
    #include <cmath>
    #include <complex>
    bool euler_flip(bool value)
    {
        return std::pow
        (
            std::complex<float>(std::exp(1.0)), 
            std::complex<float>(0, 1) 
            * std::complex<float>(std::atan(1.0)
            *(1 << (value + 2)))
        ).real() < 0;
    }

Popular pages Recent additions subscribe to a feed