CS计算机代考程序代写 Java c++ COMP6771 Advanced C++ Programming

COMP6771 Advanced C++ Programming
Week 4.1 Operator Overloading
1

Why?
In this lecture
Operator overloads allow you to decrease your code complexity and utilise well defined semantics.
What?
Many different types of operator overloads
2

Start with an example
Line 32 is our best attempt to “Add two points together and print them”
print(std::cout, point::add(p1, p2));
This is clumsy and ugly. We’d much prefer to have a semantic like this
std::cout << p1 + p2; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include
class point {
public:
point(int x, int y)
: x_{x}
, y_{y} {};
[[nodiscard]] int const x() const {
return this->x_; }
[[nodiscard]] int const y() const {
return this->y_; }
static point add(point const& p1, point const& p2);
private:
int x_;
int y_;
void print(std::ostream& os, point const& p) {
os << "(" << p.x() << "," << p.y() << ")"; point point::add(point const& p1, point const& p2) { return point{p1.x() + p2.x(), p1.y() + p2.y()}; } auto main() -> int {
point p1{1, 2};
point p2{2, 3};
};
}
}
print(std::cout, point::add(p1, p2));
std::cout << "\n"; lecture-3/demo401-point1.cpp 3.1 Start with an example Using operator overloading: Allows us to use currently understood semantics (all of the operators!) Gives us a common and simple interface to define class methods 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include
class point {
public:
point(int x, int y)
: x_{x}
, y_{y} {};
friend point operator+(point const& lhs,
point const& rhs);
friend std::ostream& operator<<(std::ostream& os, point const& p); private: int x_; int y_; }; point operator+(point const& lhs, point const& rhs) { return point(lhs.x_ + rhs.x_, lhs.y_ + rhs.y_); } std::ostream& operator<<(std::ostream& os, point const& p) { os << "(" << p.x_ << "," << p.y_ << ")"; return os; } auto main() -> int {
point p1{1, 2};
point p2{2, 3};
}
std::cout << p1 + p2 << "\n"; lecture-3/demo402-point2.cpp 3.2 Operator Overloading C++ supports a rich set of operator overloads All operator overloads must have at least one operand of its type Advantages: Reuse existing code semantics No verbosity required for simple operations Disadvantages: Lack of context on operations Only create an overload if your type has a single, obvious meaning to an operator 4.1 Friends A class may declare friend functions or classes Those functions / classes are non-member functions that may access private parts of the class This is, in general, a bad idea, but there are a few cases where it may be required Nonmember operator overloads (will be discussing soon) Related classes A Window class might have WindowManager as a friend A TreeNode class might have a Tree as a friend Container could have iterator_t as a friend
Though a nested class may be more appropriate Use friends when:
The data should not be available to everyone
There is a piece of code very related to this particular class
In general we prefer to define friends directly in the class they relate to
4.2

Operator Overload Design
Type
Operator(s)
Member / friend
I/O
<<, >>
friend
Arithmetic
+, -, *, /
friend
Relational, Equality
>, <, >=, <=, ==, != friend Assignment = member (non-const) Compound assignment +=, -=, *=, /= member (non-const) Subscript [] member (const and non-const) Increment/Decrement ++, -- member (non-const) Arrow, Deference ->, *
member (const and non-const)
Call
()
member
Use members when the operation is called in the context of a particular instance
Use friends when the operation is called without any particular instance
Even if they don’t require access to private details
5

Overload: I/O
Equivalent to .toString() method in Java
Scope to overload for different types of output and input streams
1 #include
2 #include
3
4 class point {
5 public:
6 point(int x, int y)
7 : x_{x}
8 , y_{y} {};
9 friend std::ostream& operator<<(std::ostream& os, const point& type); 10 friend std::istream& operator>>(std::istream& is, point& type);
11
12 private:
13 int x_;
14 int y_;
15 };
16
17 std::ostream& operator<<(std::ostream& os, point const& p) { 18 os << "(" << p.x_ << "," << p.y_ << ")"; 19 return os; 20 } 21 22 std::istream& operator>>(std::istream& is, point& p) {
23 // To be done in tutorials
24 }
25
26 auto main() -> int {
27 point p(1, 2);
28 std::cout << p << '\n'; 29 } lecture-3/demo403-io.cpp 6 Overload: Compound assignment Sometimes particular methods might not have any real meaning, and they should be omitted (in this case, what does dividing two points together mean). Each class can have any number of operator+= operators, but there can only be one operator+= (X) where X is a type. That's why in this case we have two multiplier compound assignment operators 1 class point { 2 public: 3 point(int x, int y) 4 : x_{x} 5 , y_{y} {}; 6 point& operator+=(point const& p); 7 point& operator-=(point const& p); 8 point& operator*=(point const& p); 9 point& operator/=(point const& p); 10 point& operator*=(int i); 11 12 private: 13 int x_; 14 int y_; 15 }; 16 17 point& point::operator+=(point const& p) { 18 x_ += p.x_; 19 y_ += p.y_; 20 return *this; 21 } 22 23 point& operator+=(point const& p) { /* what do we put here? */} 24 point& operator-=(point const& p) { /* what do we put here? */} 25 point& operator*=(point const& p) { /* what do we put here? */} 26 point& operator/=(point const& p) { /* what do we put here? */} 27 point& operator*=(int i) { /* what do we put here? */} lecture-3/demo404-compassign.cpp 7 Operator pairings Many operators should be grouped together. This table should help you work out which are the minimal set of operators to overload for any particular operator. If you overload Then you should also overload operator OP=(T, operator+(T, U) operator-(T, U) operator/(T, U) operator%(T, U) operator++() operator--() operator->()
U)
operator OP(T, U)
operator+(U, T)
operator+(T, U)
operator*(T, U)
operator/(T, U)
operator++(int)
operator++() operator–(int) operator*()
operator+(T)
operator-(T)
8

Overload: Relational & Equality
Do we want all of these?
We’re able to “piggyback” off previous definitions
Check out the spaceship operator
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include
class point {
public:
point(int x, int y)
: x_{x}
, y_{y} {}
// hidden friend – preferred
friend bool operator==(point const& p1, point const& p2) {
return p1.x_ == p2.x_ and p1.y_ == p2.y_;
// return std::tie(p1.x_, p1.y_) == std::tie(p2.x_, p2.y_);
}
friend bool operator!=(point const& p1, point const& p2) {
return not (p1 == p2);
friend bool operator<(point const& p1, point const& p2) { return p1.x_ < p2.x_ and p1.y_ < p2.y_; friend bool operator>(point const& p1, point const& p2) {
return p2 < p1; friend bool operator<=(point const& p1, point const& p2) { return not (p2 < p1); friend bool operator>=(point const& p1, point const& p2) {
}
}
}
}
} }
private:
int x_;
int y_;
};
auto main() -> int {
auto const p2 = point{1, 2};
return not (p1 < p2); auto const p1 = point{1, 2}; std::cout << "p1 == p2 " << (p1 == p2) << '\n'; std::cout << "p1 != p2 " << (p1 != p2) << '\n'; std::cout << "p1 < p2 " << (p1 < p2) << '\n'; std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; lecture-3/demo405-relation1.cpp 9 Overload: Assignment Similar to compound assignment 1 #include 2
3 class point {
4 public:
5 point(int x, int y)
6 : x_{x}
7 , y_{y} {};
8 point& operator=(point const& p);
9
10 private:
11 int x_;
12 int y_;
13 };
14
15 point& point::operator=(point const& p) {
16 x_ = p.x_;
17 y_ = p.y_;
18 return *this;
19 }
lecture-3/demo406-assign.h
10

Overload: Subscript
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
18
19
20
#include
class point {
public:
point(int x, int y)
: x_{x}
, y_{y} {};
int& operator[](int
assert(i ==
return i ==
i) {
0 or i == 1);
0 ? x_ : y_;
} private:
};
}
int operator[](int i) const {
assert(i == 0 or i == 1);
return i == 0 ? x_ : y_;
int x_;
int y_;
lecture-3/demo407-subscript.h
Usually only defined on indexable containers
Different operator for get/set Asserts are the right approach here as preconditions:
In other containers (e.g. vector), invalid index access is undefined behaviour. Usually an explicit crash is better than undefined behaviour
Asserts are stripped out of optimised builds
11

Overload: Increment/Decrement
prefix: ++x, –x, returns lvalue reference Discussed more in week 5
postfix: x++, x–, returns rvalue
Discussed more in week 5
Performance: prefix > postfix Different operator for get/set Postfix operator takes in an int
This is not to be used
It is only for function matching Don’t name the variable
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// RoadPosition.h:
class RoadPosition {
public:
RoadPosition(int km) : km_from_sydney_(km) {}
RoadPosition& operator++(); // prefix
// This is *always* an int, no
// matter your type.
RoadPosition operator++(int); // postfix
void tick();
int km() { return km_from_sydney_; }
private:
void tick_();
int km_from_sydney_;
};
// RoadPosition.cpp:
#include
RoadPosition& RoadPosition::operator++() {
this->tick_();
return *this;
}
RoadPosition RoadPosition::operator++(int) {
RoadPosition rp = *this;
this->tick_();
return rp;
}
void RoadPosition::tick_() {
++(this->km_from_sydney_);
}
1 auto main() -> int {
2
3
4
5
6
7 8}
auto rp = RoadPosition(5);
std::cout << rp.km() << '\n'; auto val1 = (rp++).km(); auto val2 = (++rp).km(); std::cout << val1 << '\n'; std::cout << val2 << '\n'; lecture-3/demo408-incdec.h lecture-3/demo408-incdec.cpp 12 Overload: Arrow & Dereferencing This content will feature heavily in week 5 Classes exhibit pointer-like behaviour when - > is overloaded
For -> to work it must return a pointer to a class type or an object of a class type that defines its own -> operator
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
delete ptr_;
std::string* operator->() const {
return ptr_;
std::string& operator*() const {
return *ptr_;
private:
std::string* ptr_;
};
auto main() -> int {
auto p = stringptr(“smart pointer”);
std::cout << *p << '\n'; std::cout << p->size() << '\n'; } #include
class stringptr {
public:
explicit stringptr(std::string const& s)
: ptr_{new std::string(s)} {}
~stringptr() {
1
2
3
4
5
6
7 8}
} }
lecture-3/demo409-arrow.cpp
13

Overload: Type Conversion
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
18
#include
class point {
public:
point(int x, int y)
: x_(x)
, y_(y) {}
explicit operator std::vector() {
} private:
};
std::vector vec;
vec.push_back(x_);
vec.push_back(y_);
return vec;
int x_;
int y_;
lecture-3/demo410-type.h
Many other operator overloads
Full list here:
https://en.cppreference.com/w/cpp/languag e/operators
Example: overload
1
2
3
4
5
6
7 8}
#include
#include
int main() {
auto p = point(1, 2);
auto vec = static_cast>(p);
std::cout << vec[0] << '\n'; std::cout << vec[1] << '\n'; lecture-3/demo410-type.cpp 14 Overload: New Function Syntax 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 delete ptr_; auto operator->() const -> std::string* {
return ptr_;
auto operator*() const -> std::string& {
return *ptr_;
#include
class stringptr {
public:
explicit stringptr(std::string const& s)
: ptr_{new std::string(s)} {}
~stringptr() {
1
2
3
4
5
6
7 8}
} }
private:
std::string* ptr_;
};
auto main() -> int {
auto p = stringptr(“smart pointer”);
std::cout << *p << '\n'; std::cout << p->size() << '\n'; } lecture-3/demo411-syntax.cpp We are able to use the new function syntax on our operator overloads as well 15 Overload: Spaceship Operator 1 #include
2 #include
3
4 class point {
5 public:
6 point(int x, int y)
7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::strong_ordering
12 friend auto operator<=>(point p1, point p2) = default;
13
14 private:
15 int x_;
16 int y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1, 2};
21 auto const p1 = point{1, 2};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } 1 #include
2 #include
3
4 class point {
5 public:
6 point(double x, double y)
7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::partial_ordering
12 friend auto operator<=>(point p1, point p2) = default;
13
14 private:
15 double x_;
16 double y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1.0, 2.0};
21 auto const p1 = point{1.0, 2.0};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } lecture-3/demo405-relation2.cpp 16 . 1 Overload: Spaceship Operator 1 #include 2 #include 3
4 class point {
5 public:
6 point(int x, int y) 7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::strong_ordering
12 friend auto operator<=>(point p1, point p2) = default; 13
14 private:
15 int x_;
16 int y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1, 2};
21 auto const p1 = point{1, 2};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } 1 #include
2 #include
3
4 class point {
5 public:
6 point(double x, double y)
7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::partial_ordering
12 friend auto operator<=>(point p1, point p2) = default;
13
14 private:
15 double x_;
16 double y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1.0, 2.0};
21 auto const p1 = point{1.0, 2.0};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } lecture-3/demo405-relation2.cpp 16 . 1 Overload: Spaceship Operator 1 #include 2 #include 3
4 class point {
5 public:
6 point(int x, int y) 7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::strong_ordering
12 friend auto operator<=>(point p1, point p2) = default; 13
14 private:
15 int x_;
16 int y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1, 2};
21 auto const p1 = point{1, 2};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } 1 #include
2 #include
3
4 class point {
5 public:
6 point(double x, double y) 7 : x_{x}
8 , y_{y} {}
9
10 // hidden friend – preferred
11 // return type deduced as std::partial_ordering
12 friend auto operator<=>(point p1, point p2) = default; 13
14 private:
15 double x_;
16 double y_;
17 };
18
19 auto main() -> int {
20 auto const p2 = point{1.0, 2.0};
21 auto const p1 = point{1.0, 2.0};
22 std::cout << "p1 == p2 " << (p1 == p2) << '\n'; 23 std::cout << "p1 != p2 " << (p1 != p2) << '\n'; 24 std::cout << "p1 < p2 " << (p1 < p2) << '\n'; 25 std::cout << "p1 > p2 ” << (p1 > p2) << '\n'; 26 std::cout << "p1 <= p2 " << (p1 <= p2) << '\n'; 27 std::cout << "p1 >= p2 ” << (p1 >= p2) << '\n'; 28 } lecture-3/demo405-relation2.cpp 16 . 1 Overload: Spaceship Operator // For int-based point auto const ordering = (p1 <=> p2) == std::strong_ordering::equal;
std::cout << "p1 <=> p2 yields equal ” << ordering << '\n'; // For double-based point auto const ordering = (p1 <=> p2) == std::partial_ordering::equivalent;
std::cout << "p1 <=> p2 yields equivalent ” << ordering << '\n'; 16 . 2 Overload: Spaceship Operator #include
Example types
Floating-point numbers Complex numbers
2D points
std::partial_ordering::less
std::partial_ordering::equivalent
std::partial_ordering::greater
std::partial_ordering::unordered
std::weak_ordering::less
std::weak_ordering::equivalent
std::weak_ordering::greater
Case-insensitive strings
std::strong_ordering::less
std::strong_ordering::equal
std::strong_ordering::greater
Integers std::string
16 . 3

Overload: Spaceship Operator
1 2 3 4 5 6 7 8 9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include
#include
class point {
public:
point(int x, int y)
: x_{x}
, y_{y} {}
friend auto operator==(point, point) -> bool = default;
friend auto operator<=>(point const p1, point const p2) -> std::partial_ordering {
auto const x_result = p1.x_ <=> p2.x_;
auto const y_result = p1.y_ <=> p2.y_;
return x_result == y_result ? x_result
}
private:
int x_;
int y_; };
: std::partial_ordering::unordered;
lecture-3/demo405-relation2.cpp
16 . 4