C++ Primer笔记10_运算符重载_赋值运算符_进入/输出操作符
1.颂值运营商
首先来福值运算符引入后面要说的运算符重载。上一节说了构造函数、拷贝构造函数;一个类要想进行更好的控制。须要定义自己的构造函数、拷贝构造函数、析构函数、当然,还有赋值运算符。常说的三大函数就是指拷贝、赋值、析构。
假设一个类不定义自己的赋值运算符。会自己生成一个默认的赋值运算操作。这个默认的赋值运算满足一般类的需求。它实现的是一个浅拷贝。可是当类的功能、作用逐渐完好时,就会出现非常多问题。所以,通过自己定义赋值运算符来控制赋值操作时类的行为是非常有必要的。当一个类的对象与对象之间发生赋值(=)运算时,就会调用重载的赋值运算符函数。
还是以上节的样例来说。看代码:
#include <iostream>
#include <new>
#include <string> using namespace std; class Person
{
public:
Person();
Person(int n, const string &str);
Person(const Person &n);
Person &operator=(const Person &p);//赋值运算符函数
~Person();
private:
int age;
string *name;
}; Person::Person():age(0), name(NULL)
{
cout << "Default Person" << endl;
} Person::Person(int n, const string &str):age(n), name(new string(str))
{
cout << "Init Person" << endl;
} Person::Person(const Person &n)
{
if(n.name)
{
name = new string(*(n.name));
age = n.age;
}
else
{
name = NULL;
age = 0;
}
} Person & Person::operator=(const Person &p)
{
if(this == &p)
{
return *this;//推断传入的对象是否是当前对象本身
}
string *tmp = new string(*p.name);//又一次分配一段空间
delete this->name;//释放原空间
this->name = tmp;
this->age = p.age; return *this;
} Person::~Person()
{
cout << "~Person " << "name: " << name << " age: " << age << endl;
delete name;
} int main()
{
Person p1(20, "SCOTT");
Person p2;
p2 = p1; return 0;
}
在这里,假设没有自己定义赋值运算符,当执行P2 = P1时,是没有错的。而错误会处在析构部分,上一篇文章中已经说明原因。
Init Person
Default Person
~Person name: 0x8264020 age: 20
~Person name: 0x8264020 age: 20
Segmentation fault (core dumped)——段错误!
自己定义赋值运算符之后。执行结果例如以下:
Init Person
Default Person
~Person name: 0x8121030 age: 20
~Person name: 0x8121020 age: 20
注意:
1)一般来说,大多数赋值运算符函数组合了析构函数和拷贝构造函数的工作。
2)假设讲一个对象赋予它自身。赋值运算符必须能正确的工作。
3)当编写赋值运算符函数时。一个好的模式是将右側对象复制到一个局部暂时对象中。拷贝完毕后,销毁左側对象的现有成员就是安全的了。
然后将数据从暂时对象复制到左側对象。
2.运算符重载
上面是众多运算符重载的一个实例。重载的运算符是具有特殊名字的函数:它们的名字是由keywordoperator和其后要定义的运算符号共同组成。
它与普通函数一样也有返回值、參数列表、以及函数体。
重载运算符函数的參数数量与该运算符的作用的运算对象数量一样多。一元运算符有一个參数。二元运算符有两个。
对于二元运算符来说,左側运算对象传递给第一个參数,右側运算对象传递给第二个參数。
假设一个运算符函数是成员函数,则它的第一个(左側)运算对象绑定到隐式的this指针上。因此,成员运算符函数的參数比运算符的运算对象少一个。(如上例中的=运算符)
2.1 输入、输出运算符
IO标准库分别使用>>和<<运行输入和输出操作。
类能够按须要来自己定义输入、输出运算符。
样例:
#include <iostream>
#include <new>
#include <string> using namespace std; class Person
{
public:
Person();
Person(int n, const string &str);
Person(const Person &n);
Person &operator=(const Person &p);
~Person(); string getName()const;
friend ostream &operator<<(ostream &out, const Person &p);//输出运算符
friend istream &operator>>(istream &in, Person &p);//输入运算符
private:
int age;
string *name;
}; Person::Person():age(0), name(NULL)
{
cout << "Default Person" << endl;
} Person::Person(int n, const string &str):age(n), name(new string(str))
{
cout << "Init Person" << endl;
} Person::Person(const Person &n)
{
if(n.name)
{
name = new string(*(n.name));
age = n.age;
}
else
{
name = NULL;
age = 0;
}
} Person & Person::operator=(const Person &p)
{
if(this == &p)
{
return *this;
}
string *tmp = new string(*p.name);
delete this->name;
this->name = tmp;
this->age = p.age; cout << "operator =" << endl; return *this;
} Person::~Person()
{
cout << "~Person " << "name: " << name << " age: " << age << endl;
delete name;
} string Person::getName()const
{
if(name)
{
return *name;
}
return string();
}
//重载输出运算符
ostream &operator<<(ostream &out, const Person &p)
{
out << "p.age: " << p.age << ", p.name: " << p.getName();
return out;
}
//重载输入运算符
istream &operator>>(istream &in, Person &p)
{
string s;
cout << "please input age and name:";
in >> p.age >> s;
if(in)//推断是否读取正确
{
p.name = new string(s);
}
else
{
p = Person();
} return in;
} int main()
{
Person p1(20, "SCOTT");
Person p2(10, "Kate");
Person p3;
/*
cout << p1 << endl;
cout << p2 << endl;
cout << p3 << endl;
*/
cin >> p3;
cout << p3 << endl; return 0;
}
执行程序,输入12 Mike, 结果例如以下:
Init Person
Init Person
Default Person
please input age and name:12 Mike
p.age: 12, p.name: Mike
~Person name: 0x939a088 age: 12
~Person name: 0x939a048 age: 10
~Person name: 0x939a020 age: 20
总结:
1.输入、输出运算符必须是非成员函数。
2.输入、输出运算符一般声明为友元类型。
3.输出运算符函数中第二个參数能够声明为const型,由于不须要改变其值。而输入运算符的第二个參数不能为const,由于它要接受输入。另外,返回值最好是引用,避免了值拷贝过程。
版权声明:本文博客原创文章,博客,未经同意,不得转载。
C++ Primer笔记10_运算符重载_赋值运算符_进入/输出操作符的更多相关文章
- C++ Primer笔记13_运算符重载_总结
总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 :: 和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则例如以下: 运算符 建议使用 ...
- C++ Primer笔记12_运算符重载_递增递减运算符_成员訪问运算符
1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.可是由于他们改变的正好是所操作对象的状态.所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本号,因此.我们应该 ...
- C++学习笔记之运算符重载
一.运算符重载基本知识 在前面的一篇博文 C++学习笔记之模板(1)——从函数重载到函数模板 中,介绍了函数重载的概念,定义及用法,函数重载(也被称之为函数多态)就是使用户能够定义多个名称相同但特征标 ...
- 《Inside C#》笔记(十一) 运算符重载
运算符重载与之前的索引器类似,目的是为了让语言本身使用起来更方便直接,也是一种语法糖. 一 运算符重载(Operator Overloading) 运算符重载的存在,使得现有的各种运算符可以被重新定义 ...
- C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)
运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...
- lintcode-208-赋值运算符重载
208-赋值运算符重载 实现赋值运算符重载函数,确保: 新的数据可准确地被复制 旧的数据可准确地删除/释放 可进行 A = B = C 赋值 说明 本题只适用于C++,因为 Java 和 Python ...
- C++学习(12)—— 运算符重载
运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 1.加号运算符重载 作用:实现两个自定义数据类型相加的运算 #include <iostream> #i ...
- 新标准C++程序设计读书笔记_运算符重载
形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { publ ...
- c++中的运算符重载operator2(翁恺c++公开课[31-33]学习笔记)
上一篇operator1中,大概说了下重载的基本用法,接下来对c++中常见的可重载运算符归一下类,说一下它们的返回值,讨论下较为复杂的运算符重载上的坑
随机推荐
- Js三级联动菜单
效果演示: <SCRIPT LANGUAGE="JavaScript"> <!-- function CreateSelect(_FormName,_SName, ...
- js获取当前日期,网页头部用
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/ ...
- PLSQL数据导入
导入数据 (1) 首先以管理员身份登录plsql; (2) 新建命令窗口 (3) 创建用户,设置帐号,密码 创建语句:create user usernameidenti ...
- QNX 多线程 (线程1每隔20ms读取 number;线程2每隔10ms计算一次)
#include <pthread.h>#include <stdio.h>#include <sys/time.h>#include <string.h&g ...
- Java常用代码段 - 未完待续
记录一些自己写项目常用的代码段. 格式化常用日期格式 Date date = new Date(System.currentTimeMillis()); DateFormat d3 = DateFor ...
- [置顶] 简单解析linux下进程通信方法
linux下的进程通信手段基本上是从Unix平台上的进程通信手段继承而来的.而对Unix发展做出重大贡献的两大主力AT&T的贝尔实验室及BSD(加州大学伯克利分校的伯克利软件发布中心)在进程间 ...
- django url调度
Django的url配置相同遵循着DRY(dont repeat yourself)的规则.下面都是官方文档的样例: 首先介绍的是Django怎样处理http的请求: 1.在setting里定义ROO ...
- ThinkPhp学习11
原文:ThinkPhp学习11 一.模板的使用 (重点) a.规则 模板文件夹下[TPL]/[分组文件夹/][模板主题文件夹/]和模块名同名的文件夹[Index]/和方法名同名的文件[i ...
- Linux多线程服务端编程:使用muduo C++网络库
内容推荐本 书主要讲述采用现代C++在x86-64 Linux上编写多线程TCP网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread.这 ...
- 关于__stdcall和__cdecl调用方式的理解
__stdcall和__cdecl都是函数调用约定关键字,先给出这两者的区别,然后举实例分析: __stdcall:参数由右向左压入堆栈:堆栈由函数本身清理. __cdecl:参数也是由右向左压入堆栈 ...