Classes and Objects

Introducing C++: class point

Following a complete C++ re-implementation of the struct point story that we saw earlier.

It has:

  • Constructors: programmable initialization

  • Methods: operations on objects

  • Operators

#ifndef POINT_H
#define POINT_H

#include <ostream>
#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; }

    bool operator==(point other) const { return _x == other._x && _y == other._y; }
    bool operator!=(point other) const { return !operator==(other); }

    point& operator+=(point vec)
    {
        _x += vec._x;
        _y += vec._y; 
        return *this;
    }

    point operator+(point other) const { return point(_x+other._x, _y+other._y); }
    point operator-(point other) const { return point(_x-other._x, _y-other._y); }

    double abs() const
    {
        int hyp = _x*_x + _y*_y;
        return sqrt(hyp);
    }

    double distance(point other) const
    {
        point diff = *this - other;
        return diff.abs();
    }

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

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

static inline std::ostream& operator<<(std::ostream& s, point p)
{
    s << '(' << p.x() << ',' << p.y() << ')';
    return s;
}

#endif

Access Specifiers: public And private

class point
{
public:
    int x() const { return _x; }  // permit read-only access to _x
    int y() const { return _y; }  // permit read-only access to _y
private:
    int _x;
    int _y;
};

public

Public access on object possible

private

Only class methods can access

protected

Only class methods, and derived classes (⟶ later)

point p{1,2};
p._x;   // <--- error: ‘int point::_x’ is private within this context
point p{1,2};
p.x();   // ok: using public access method

Default Constructor

  • C does not help with initialization

  • ⟶ leaves things uninitialized if not explicitly initialized

    struct point p;  // <--- uninitialized!!
    
  • C++: default constructor

    point p;         // <--- default constructor invoked
    

Default constructor implementation: pre C++11

  • Initializer list used to set members to their defaults

class point
{
public:
    point() : _x{0}, _y{0} {}    // <--- initializer list
private:
    int _x;
    int _y;
};

Default constructor implementation: since C++11

  • Member default initialization right in class

  • = default

class point
{
public:
    point() = default;   // <--- use default values from member definitions
private:
    int _x{};            // <--- _x defaults to 0
    int _y{};            // <--- _y defaults to 0
};
point p1{2,4};  // -> point(int x, int y)
point p2;       // -> point(); default constructor

Custom Constructor: Usage

  • User defined initialization

  • Programmer responsible for parameter signature

C++ usage

C “usage”

#include <gtest/gtest.h>
#include "point.h"

TEST(point_cpp_suite, constructor_coordinates)
{
    point p1{3,4};    // <--- c++11 "brace initialization" style
    ASSERT_EQ(p1.x(), 3);
    ASSERT_EQ(p1.y(), 4);

    point p2(3,4);    // <--- good-ol' c++03 style
    ASSERT_EQ(p2.x(), 3);
    ASSERT_EQ(p2.y(), 4);
}
#include <gtest/gtest.h>

struct point
{
    int x;
    int y;
};

struct point point_create(int x, int y)
{
    struct point p = {x,y};
    return p;
}

TEST(point_c_suite, c_constructor)
{
    struct point p = point_create(1,2);
    
    ASSERT_EQ(p.x, 1);
    ASSERT_EQ(p.y, 2);
}

Custom Constructor: Implementation

Initializer list?

class point
{
public:
    point(int x, int y)
     : _x{x}, _y{y}           // <--- initializer list
     {}                       // <--- constructor body (here: empty)
};
  • Members _x and _y initialized with respective parameters

  • Just like assignment in constructor body

  • ⟶ cannot assign to const members though

Access Methods For Otherwise Private Members

  • Members in private: section inaccessibile from outside class definition

  • Read access desired though

  • access methods

  • ⟶ note the const: promise that a call won’t alter the object

class point
{
public:
    int x() const { return _x; }
    int y() const { return _y; }
private:
    int _x;
    int _y;
};

Methods: Operations On An Object

  • Methods are functions that are tied to objects

  • … rather than free functions that take objects as parameters

  • Note the const again

    • C++: const method

    • C: const object pointer

C++

C

Implementation
class point
{
public:
    double abs() const
    {
        int hyp = _x*_x + _y*_y;
        return sqrt(hyp);
    }
private:
    int _x{};
    int _y{};
};
Usage
#include <gtest/gtest.h>
#include "point.h"

TEST(point_cpp_suite, abs)
{
    const point p{3,4};
    double abs = p.abs();

    ASSERT_FLOAT_EQ(abs, 5.0);
}
Usage
#include <gtest/gtest.h>

#include <math.h>

struct point
{
    int x;
    int y;
};

double point_abs(const point* self)
{
    int hyp = self->x * self->x + self->y * self->y;
    return sqrt(hyp);
}

TEST(point_c_suite, abs)
{
    const point p = {3,4};
    double abs = point_abs(&p);

    ASSERT_FLOAT_EQ(abs, 5.0);
}

Operator Overloading

  • In C, everything is explicit

  • When you mean vector addition, you say point_move()

  • In C++, you say +=

C++

C

Implementation
class point
{
public:
    point& operator+=(point vec)
    {
        _x += vec._x;
        _y += vec._y;
        return *this;
    }
};
Usage
#include <gtest/gtest.h>
#include "point.h"

TEST(point_cpp_suite, move_op_pluseq)
{
    point p{1,2};
    const point vec{3,4};
    const point& p1 = p += vec;

    ASSERT_EQ(p.x(), 4);
    ASSERT_EQ(p.y(), 6);

    bool b = (p == p1);
    ASSERT_TRUE(b);

    ASSERT_EQ(&p1, &p);  // operator+=() returns point& !!
}
Usage
#include <gtest/gtest.h>

struct point
{
    int x;
    int y;
};

void point_move(point* self, int x, int y)
{
    self->x += x;
    self->y += y;
}

TEST(point_c_suite, move)
{
    point p = {1,2};

    point_move(&p, 3, 4);

    ASSERT_EQ(p.x, 4);
    ASSERT_EQ(p.y, 6);
}

And printf()?!

  • Everybody hates it anyway ("%ld" is not long double 🤮)

  • C++ knows more about types

  • C++ supports function (and operator) overloading

    • ⟶ Multiple definitions of the same function name, only with different parameters

  • <iostream>, with operator<<()

Shift that thing out, man!

std::cout << "D.x: " << D.x() << ", D.y: " << D.y() << std::endl;