C++ 14 重载操作符与转换

重载操作符

Cat.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#pragma once
#include <string>
#include <iostream>
using std::string; using std::ostream; using std::istream;
class Cat {
public:
Cat() {}
Cat(string name) :name(name) {};
// 重载输入、输出操作符
// 若供外部使用,写非成员函数的样子 添加友元
// 成员函数的写法只要一个左操作符参数
friend ostream& operator<<(ostream& out, Cat& cat);
friend istream& operator>>(istream& in , Cat& cat);

private:
string name;
};

Cat.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
#include "Cat.h"

ostream & operator<<(ostream & out, Cat & cat)
{
out << cat.name;
return out;
}

istream & operator >> (istream & in, Cat & cat)
{
in >> cat.name;
return in;
}

重载函数的使用 main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <sstream>
#include "Cat.h"
using namespace std;
int main()
{
Cat cat ;
cin >> cat; // 输入

cout << cat << endl; // 输出
return 0;
}

算术操作符重载

Book.h

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
#pragma once
#include <string>
#include <iostream>
using std::string; using std::ostream; using std::istream;

class Book
{
public:
Book(const Book& b) { name = b.name; count = b.count; }
Book(string name, int count) :name(name), count(count) {}
friend Book operator+(const Book& lb, const Book& rb);
friend bool operator==(const Book& lb, const Book& rb);
friend ostream& operator<<(ostream& out, Book& b);
Book operator+=(const Book&rb);
private:
string name;
int count; // 数量
};

Book operator+(const Book & lb, const Book & rb)
{
Book b(lb);
b += rb;
return b;
}

Book Book::operator+=(const Book & rb)
{
count += rb.count;
return *this;
}

inline bool operator==(const Book & lb, const Book & rb)
{
return lb.name == rb.name && lb.count == rb.count;
}

ostream & operator<<(ostream & out, Book & b)
{
out << "name:" << b.name << ",count:" << b.count ;
return out;
}

算术符号重载后的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <sstream>
#include "Book.h"
using namespace std;
int main()
{
Book b1("piao", 1);
Book b2("piao", 2);
Book b3 = b1 + b2;
Book b4("piao", 3);
bool is = b3 == b4;
cout << "重载加号,数量想加后为:" << b3 << endl;
cout << "重载相等符号,b3 == b4:" << is << endl;
return 0;
}

下标操作费、成员访问操作符

下标操作符重载示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#pragma once
#include<vector>
using namespace std;
class Foo {
public:
int &operator[](const size_t);
const int &operator[](const size_t) const;
private:
vector<int> data;
};

int & Foo::operator[](const size_t index)
{
return data[index];
}
inline const int & Foo::operator[](const size_t index) const
{
return data[index];
}

使用解引用操作符与箭头符号重载,构建智能指针

指针计数类 ScrPtr.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
#include "ScreenPtr.h"
#include "Screen.h"
class ScrPtr
{
// 指针计数类
friend class ScreenPtr;
Screen *sp;
size_t use;
ScrPtr(Screen *p) :sp(p), use(1) {};
~ScrPtr();
};


ScrPtr::~ScrPtr()
{
delete sp;
}

指针封装对象 ScreenPtr.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#pragma once
#include "Screen.h"
#include "ScrPtr.h"
class ScreenPtr
{
public:
ScreenPtr(Screen *p) :ptr(new ScrPtr(p)) {}
ScreenPtr(const ScreenPtr& o) :ptr(o.ptr) { ++ptr->use; }
~ScreenPtr() {
// 若指针计数为0 则删除
if (--ptr->use == 0)
delete ptr;
};
// 重载解引用操作符 返回安全指针
Screen &operator*() { return *ptr->sp; }
// 重载箭头操作符 ->右操作数不是表达式,是对应类成员的标识符
Screen *operator->() { return ptr->sp; }
private:
ScrPtr *ptr;
};

C++ 13 复制控制

复制构造函数

复制构造函数,传入同类型其他对象,初始化成员 。

1
Message(const Message &m) :contents(m.contents), folders(m.folders){} ;

操作符重载

1
2
// 操作符重载,左操作数为this,又操作数为参数
Message& operator=(const Message&);

析构函数

变量在超出作用域时自动撤销,动态分配对象被删除时调用。

1
~Message();

消息处理示例

Message.h

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
44
#pragma once
#include<string>
#include<set>
#include<vector>
#include<iostream>
#include "Folder.h"
using namespace std;

class Message
{
friend class Folder;
public:
Message(const string &str = "") :contents(str) {};
// 复制构造函数,传入同类型其他对象,初始化成员
Message(const Message &m) :contents(m.contents), folders(m.folders) {
// 将消息 放入对应文件夹中
put_msg_in_folders(folders);
};
// 操作符重载,左操作数为this,又操作数为参数
Message& operator=(const Message&);
// 析构函数
~Message();

// 将消息保存到文件夹中
void save(Folder&);
// 从文件夹中移除消息
void remove(Folder&);

vector<Folder*> get_folders();
string print_message() { return contents; }
void debug_print();

private:
string contents; // 消息内容
set<Folder*> folders; // 消息对应文件夹

// 将消息放入文件夹
void put_msg_in_folders(const set<Folder*>&);
// 从文件夹移除消息
void remove_msg_from_Folders();

void addFolder(Folder *f) { folders.insert(f); };
void remFolder(Folder *f) { folders.erase(f); };
};

Message.cpp

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
44
45
46
47
48
49
50
51
52
53
54
55
56
#include "Message.h"
#include "Folder.h"

Message::~Message()
{
remove_msg_from_Folders();
}

// 对原消息赋值,右操作数不改变,原消息改变成员和对应的文件夹关系
Message & Message::operator=(const Message &rhs)
{
if (&rhs != this)
{
remove_msg_from_Folders(); // 将原消息从文件夹中删除
contents = rhs.contents; // 复制成员
folders = rhs.folders;
put_msg_in_folders(rhs.folders); // 将原消息放入新文件夹中
}
return *this;
}


void Message::save(Folder &f)
{
folders.insert(&f); // 添加消息与文件夹的关联
f.addMsg(this); // 添加文件夹与消息的关联
}

void Message::remove(Folder &f)
{
folders.erase(&f); // 删除消息与文件夹的关联
f.remMsg(this); // 删除文件夹与消息的关联
}

vector<Folder*> Message::get_folders()
{
return vector<Folder*>(folders.begin(), folders.end());
}

void Message::debug_print()
{
cerr << "Message:\n\t" << contents << endl;
cerr << "Appears in " << folders.size() << " Folders " << endl;
}

void Message::put_msg_in_folders(const set<Folder*> &rhs)
{
for (set<Folder*>::const_iterator beg = rhs.begin(); beg != rhs.end(); ++beg)
(*beg)->addMsg(this); // 遍历文件夹 添加消息
}

void Message::remove_msg_from_Folders()
{
for (set<Folder*>::const_iterator beg = folders.begin(); beg != folders.end(); ++beg)
(*beg)->remMsg(this); // 遍历文件夹 删除消息
}

Folder.h

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
#pragma once
#include <set>
#include "Message.h"

class Folder
{
friend class Message; // 设为友元以便访问私有成员
public:
~Folder();
// 复制构造函数
Folder(const Folder&);
Folder& operator=(const Folder&);

Folder() {};
// 添加消息,保存消息与文件夹的关联
void save(Message& msg);
// 删除消息,删除消息与文件夹的关联
void remove(Message& msg);

vector<Message*> messages();
void debug_print();

private:
typedef set<Message*>::const_iterator Msg_iter;
set<Message*> msgs;
// 建立与消息的关联
void copy_msgs(const set<Message*>&);
// 删除消息列表与文件夹的关联
void empty_msgs();
void addMsg(Message *m) { msgs.insert(m); };
void remMsg(Message *m) { msgs.erase(m); };
};

Folder.cpp

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
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "Folder.h"
#include "Message.h"

Folder::~Folder()
{
empty_msgs();
}

Folder::Folder(const Folder &f)
{
copy_msgs(f.msgs);
}

Folder & Folder::operator=(const Folder &f)
{
if (&f != this)
{
empty_msgs();
copy_msgs(f.msgs);
}
return *this;
}

void Folder::save(Message & msg)
{
msgs.insert(&msg);
msg.addFolder(this);
}

void Folder::remove(Message & msg)
{
msgs.erase(&msg);
msg.remFolder(this);
}

vector<Message*> Folder::messages()
{
return vector<Message*>(msgs.begin(), msgs.end());
}

void Folder::debug_print()
{
cerr << "Folder contains " << msgs.size() << "messages " << endl;
int ctr = 1;
for (Msg_iter beg = msgs.begin(); beg != msgs.end(); ++beg)
cerr << "Message " << ctr++ << ":\n\t" << (*beg)->print_message << endl;
}

void Folder::copy_msgs(const set<Message*> &m)
{
for (Msg_iter beg = m.begin(); beg != m.end(); ++beg)
(*beg)->save(*this); // 遍历消息保存到文件夹中
}

void Folder::empty_msgs()
{
Msg_iter it = msgs.begin();
while (it != msgs.end())
{
Msg_iter next = it;
++next;
(*it)->remove(*this); // 遍历消息,删除消息与文件夹的关联
it = next;
}
}

智能指针

通过记录指针被复制次数,避免产生悬垂指针。

普通含有指针成员的类 HasPtr.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once
class HasPtr
{
public:
HasPtr(int *p, int i) :ptr(p), val(i) {}

int *get_ptr()const { return ptr; }
int get_val() const { return val; }

void set_ptr(int *p){ptr = p; }
void set_val(int v) { val = v; }

int get_ptr_val() const { return *ptr; }
void set_ptr_val(int val)const { *ptr = val; }
private:
int *ptr;
int val;
};

main.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
#include <sstream>
#include "HasPtr.h"

using namespace std;
int main()
{
int obj = 0;
HasPtr ptr1(&obj, 42);
HasPtr ptr2(ptr1); // 默认的复制构造函数,将复制两个成员,指针将指向同一个对象

ptr1.set_ptr_val(22);
cout << ptr2.get_ptr_val() << endl; // 22
return 0;
}

引入指针计数器 U_Ptr.h

1
2
3
4
5
6
7
8
9
10
11
#pragma once
#include "HasPtr.h"
// 指针计数类
class U_Ptr
{
friend class HasPtr;
int *ip;
size_t use;
U_Ptr(int *p) :ip(p), use(1) {};
~U_Ptr() { delete ip; };
};

HasPtr.h

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
#pragma once
#include "U_Ptr.h"

class HasPtr
{
public:
HasPtr(int *p, int i) :ptr(new U_Ptr(p)), val(i) {}
HasPtr(const HasPtr &orig) :ptr(orig.ptr), val(orig.val) {}

HasPtr& operator=(const HasPtr&);

~HasPtr() { if (--ptr->use == 0) delete ptr; }
private:
U_Ptr *ptr;
int val;
};

HasPtr& HasPtr::operator=(const HasPtr &rhs)
{
++rhs.ptr->use;
if (--ptr->use == 0)
delete ptr;
ptr = rhs.ptr;
val = rhs.val;
return *this;
}

我好懒

C++ 12 类

类定义

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
44
45
46
47
48
49
50
51
52
#pragma once

#include <string>

using namespace std;

class Screen {
// 设置位友元
friend class Window_Mgr;

public:
// 默认构造函数
Screen() : contents("hello class"), cursor(0), width(5) {}
// 构造函数,默认实参 只能放在后面
// explicit 抑制构造函数定义的隐式转换
explicit Screen(string text, int cur = 0, int w = 5) : contents(text), cursor(cur), width(w) {}

typedef std::string::size_type index;
char get() const { return contents[cursor]; }
// 重载成员函数
inline char get(index x, index y) const;
// 显示指定内联函数
index get_cursor() const;

Screen& move(index row, index offset); // 将光标移动到某行某位

Screen& set(char); // 对光标指向位置赋值

Screen& display(std::ostream &os) { do_display(os); return *this; }
// 基于const的重载
const Screen& display(std::ostream &os) const { do_display(os); return *this; }

private:
string contents;
index cursor;
index width;
void do_display(std::ostream &os)const
{
os << contents << endl;
}
};

inline char Screen::get(index x, index y) const
{
index row = x * width;
return contents[row + y];
}

inline Screen::index Screen::get_cursor() const
{
return cursor;
}

类实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "Screen.h"

Screen & Screen::move(index row, index offset)
{
index skip = row * width;
cursor = skip + offset;
// this 指针的使用
return *this;
}

Screen & Screen::set(char c)
{
contents[cursor] = c;
return *this;
}

类使用

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
#include <iostream>
#include <sstream>
#include "Screen.h"
#include "Account.h"

using namespace std;

void display(Screen screen);

int main()
{
Screen screen;
cout << "get() = " << screen.get() << endl;
cout << "get(row,offset) = " << screen.get(0, 1) << endl;
screen.move(0, 4).set('a');
cout << "get() = " << screen.get() << endl;

Screen myscreen("hello xiaohui");
myscreen.set('*').display(std::cout);

const Screen const_screen;
const_screen.display(std::cout);

string content = "good morning";
// display(content); // 隐式转换为 Screen对象 explicit 抑制构造函数定义的隐式转换
display(Screen(content)); // 显式转换

Account ac1;
double rate = ac1.rate();
rate = Account::rate();

return 0;
}

void display(Screen screen)
{
screen.display(cout);
}

友元

1
2
3
4
5
6
7
8
9
10
#pragma once
#include "Screen.h";
class Window_Mgr {
public:
Window_Mgr& relocate(Screen::index wid, Screen& s) {
// Window_Mgr 为 Screen友元 ,可访问私有变量
s.width += wid;
return *this;
}
};

静态变量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once
#include <string>
using namespace std;
class Account {
public:
// 类成员直接使用静态变量
void applyint() { amount += amount * interestRate; }
// 静态函数没有this指针,不能引用成员变量
static double rate() { return interestRate; }
static void rate(double);
private:
std::string owner;
double amount;
static double interestRate; // 静态变量 Account类型全体对象共享
static double initRate();
};