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 access on object possible |
|
Only class methods can access |
|
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 parametersJust 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 definitionRead 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
againC++:
const
methodC:
const
object pointer
C++ |
C |
---|---|
class point
{
public:
double abs() const
{
int hyp = _x*_x + _y*_y;
return sqrt(hyp);
}
private:
int _x{};
int _y{};
};
#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);
}
|
#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 |
---|---|
class point
{
public:
point& operator+=(point vec)
{
_x += vec._x;
_y += vec._y;
return *this;
}
};
#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& !!
}
|
#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 notlong double
🤮)C++ knows more about types
C++ supports function (and operator) overloading
⟶ Multiple definitions of the same function name, only with different parameters
<iostream>
, withoperator<<()
Shift that thing out, man!
std::cout << "D.x: " << D.x() << ", D.y: " << D.y() << std::endl;