Methods

Objects - Data and Methods

C

  • Object ⇔ struct

  • Operations on objects: free functions

  • ⟶ can be defined anywhere

    struct point p = {1,2};
    point_move(&p, 3, 4); // <--- not syntactically *bound* to p
    

C++

  • Classes: data and methods

  • Methods: functions bound to objects

    point p{1,2};
    p.move(3,4);
    

class point Again

Reiterating class point from Classes and Objects:

  • What is a point? ⟶ x and y

  • What is the responsibility of a point?

    • contain x and y

    • move itself

    • compute its distance to origin

    • … or from another point …

Access Methods (“Getters”) WRONG

  • Members are private ⟶ outside access prohibited

  • Read-only access desired, though

  • ⟶ Public access methods

    #pragma once
    
    class point
    {
    public:
        point() = default;                                 // <-- generates default ctor ...
        point(int x, int y) : _x(x), _y(y) {}
    
        int x() { return _x; }                             // <-- WRONG!
        int y() { return _y; }                             // <-- WRONG!
    
    private:
        int _x{};                                          // <-- ... with these default values
        int _y{};                                          // <-- ...
    };
    
  • Getting x and y values: call getters

    #include "point.h"
    #include <iostream>
    
    int main()
    {
        point p{2, 4};
        std::cout << '(' << p.x() << ',' << p.y() << ")\n";
        return 0;
    }
    

Access Methods (“Getters”): const Objects

  • const objects: must not be changed

  • ⟶ guarantee, enforced by the compiler

#include "point.h"
#include <iostream>

int main()
{
    const point p{2, 4};                               // <-- note **const**!
    std::cout << '(' << p.x() << ',' << p.y() << ")\n";
    return 0;
}
.../main-error.cpp:8:28: error: passing ‘const point’ as ‘this’ argument discards qualifiers [-fpermissive]
    8 |     std::cout << '(' << p.x() << ',' << p.y() << ")\n";
      |                         ~~~^~

Access Methods (“Getters”): const Methods

  • const objects can only be accessed with const method

  • ⟶ leave the object itself (this) unchanged

#pragma once

class point
{
public:
    point() = default;
    point(int x, int y) : _x(x), _y(y) {}

    int x() const { return _x; }                       // <-- const
    int y() const { return _y; }                       // <-- const

private:
    int _x{};
    int _y{};
};

Modifying Method (p.move(...))

  • “Point, move yourself by x and y

  • Usage …

#include "point.h"
#include <iostream>

int main()
{
    point p{2, 4};
    p.move(1, 2);
    std::cout << '(' << p.x() << ',' << p.y() << ")\n";
    return 0;
}
  • Implementation (inline)

#pragma once

class point
{
public:
    point() = default;
    point(int x, int y) : _x(x), _y(y) {}

    int x() const { return _x; }
    int y() const { return _y; }

    void move(int x, int y)
    {
        _x += x;
        _y += y;
    }

private:
    int _x{};
    int _y{};
};

Non-Inline Implementation

  • Implementation in header file is inline

  • ⟶ code inserted at call site

  • ⟶ large binary size (not for move(x,y), but sure for larger methods)

#pragma once

class point
{
public:
    point() = default;
    point(int x, int y) : _x(x), _y(y) {}

    int x() const { return _x; }
    int y() const { return _y; }

    void move(int x, int y);                           // <-- declaration

private:
    int _x{};
    int _y{};
};
#include "point.h"

void point::move(int x, int y)                         // <-- implementation
{
    _x += x;
    _y += y;
}

Overloading move() ⟶ Vector Addition

  • Why not use a point instance as a vector?

  • move(point vec)

#pragma once

class point
{
public:
    point() = default;
    point(int x, int y) : _x(x), _y(y) {}

    int x() const { return _x; }
    int y() const { return _y; }

    void move(int x, int y) { _x += x; _y += y; }
    void move(point vec)    { move(vec.x(), vec._y); } // <-- overload

private:
    int _x{};
    int _y{};
};

Moving const point Objects?

#include "point.h"
#include <iostream>

int main()
{
    const point p{2, 4};                               // <-- move?
    const point vec{1, 2};
    p.move(vec);
    std::cout << '(' << p.x() << ',' << p.y() << ")\n";
    return 0;
}
.../main-error.cpp:8:11: error: passing ‘const point’ as ‘this’ argument discards qualifiers [-fpermissive]
    8 |     p.move(vec);
      |     ~~~~~~^~~~~
  • As above (accessors): cannot call non-const method on const object

#include "point.h"
#include <iostream>

int main()
{
    point p{2, 4};                                     // <-- cannot be const
    const point vec{1, 2};                             // <-- can be const
    p.move(vec);
    std::cout << '(' << p.x() << ',' << p.y() << ")\n";
    return 0;
}

Finally: point::distance()

What we want …

  • distance from another point

  • distance from origin

  • ⟶ overload

  • const method (though Heisenberg says we always modify through measurement)

#include "point.h"
#include <iostream>

int main()
{
    const point p{2, 4};                               // <-- not altered
    std::cout << "distance from origin: " << p.distance() << '\n';
    std::cout << "distance from (1,2): "
              << p.distance(point(1,2))                // <-- nameless *temporary* object
              << '\n';
    return 0;
}
#pragma once

#include <cmath>

class point
{
public:
    point() = default;
    point(int x, int y) : _x(x), _y(y) {}

    int x() const { return _x; }
    int y() const { return _y; }

    void move(int x, int y) { _x += x; _y += y; }
    void move(point vec)    { move(vec.x(), vec._y); } // <-- overload

    double distance(point other) const
    {
        return std::sqrt(
            std::pow(std::fabs(_x - other._x), 2) +
            std::pow(std::fabs(_y - other._y), 2)
        );
    }

    double distance() const
    {
        return distance(point(0,0));
    }

private:
    int _x{};
    int _y{};
};

const Correctness vs. Pollution

  • const pollution

    • “being correct is very cumbersome”

    • not using const is arrogant (“the compiler cannot help me because I am better”)

  • Nice goodie offered by the language

  • Compiler helps me verify that my code is correct

  • const correctness