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++中常见的可重载运算符归一下类,说一下它们的返回值,讨论下较为复杂的运算符重载上的坑
随机推荐
- xvfb 初步探究
有时候我们不关注程序是否有界面(比如自动化测试),只要程序在运行就可以了 很感谢 xvfb 这个工具给我们提供了相关的功能 比如在没有 X server 的机器上运行 gedit, 可以用下面的命令 ...
- Maven的生命周期
每次读.每次忘,Mark一下以后忘记就不翻书了! Maven有三套相互独立的生命周期,各自是:clean.default.site. clean主要是清理项目. default是Maven最核心的的构 ...
- 爬虫框架: DotnetSpider
[开源 .NET 跨平台 数据采集 爬虫框架: DotnetSpider] [一] 初衷与架构设计 一 ,为什么要造轮子 有兴趣的同学可以去各大招聘网站看一下爬虫工程师的要求,大多是JAVA,PYTH ...
- 浅析Delphi Container库(有开源的DCLX)
与Java和C++相比,Delphi对容器的支持实在少得可怜.Java有强大的集合框架,C++更有STL,Delphi有什么呢,不就是TList几个小巧的列表类,而TCollection系列的类更多只 ...
- 与众不同 windows phone (27) - Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏
原文:与众不同 windows phone (27) - Feature(特性)之搜索的可扩展性, 程序的生命周期和页面的生命周期, 页面导航, 系统状态栏 [索引页][源码下载] 与众不同 wind ...
- 进一步解 apt-get 的几个命令
用 apt-get 也非常久了,没多想它的实现,近期遇到 gstreamer 装不上的问题.才多看看了它 apt-get 就是从网上下载包,并安装到本地 手工下载 dpkg 包,而后 "dp ...
- 关于PHP的内置服务器的使用
今天刚开始正式学习PHP(之前有一点了解),推荐学习的网站是w3school.一开始不知道tomcat服务器不支持PHP脚本,直接把.php文件放到tomcat里面去运行,结果嵌入的php代码段没有什 ...
- 使用Python在2M内存中排序一百万个32位整数
译言网 | 使用Python在2M内存中排序一百万个32位整数 使用Python在2M内存中排序一百万个32位整数 译者:小鼠 发表时间:2008-11-13浏览量:6757评论数:2挑错数:0 作者 ...
- ie浏览器提交参数和其它浏览器的区别
场景描述: 用户注册模块(ajax提交方式,post方法),在url后追加了一个参数,如:url+‘btnvalue=中文参数’,如此在非ie浏览器注册时,功能完好,但在ie下注册不成功.调式后发现在 ...
- adnroid仿miui的dialog
先来看下效果图: 当中show和dismiss的时候有动画效果. 原先试过使用PopupWindow来做,可是使用的时候不是那么舒服,毕竟不是dialog嘛. 所以这次尝试还是使用dialog来做 , ...