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_运算符重载_赋值运算符_进入/输出操作符的更多相关文章

  1. C++ Primer笔记13_运算符重载_总结

    总结: 1.不能重载的运算符: . 和 .* 和 ?: 和 ::  和 sizeof 和 typeid 2.重载运算符有两种基本选择: 类的成员函数或者友元函数, 建议规则例如以下: 运算符 建议使用 ...

  2. C++ Primer笔记12_运算符重载_递增递减运算符_成员訪问运算符

    1.递增递减运算符 C++语言并不要求递增递减运算符必须是类的成员.可是由于他们改变的正好是所操作对象的状态.所以建议设定为成员函数. 对于递增与递减运算符来说,有前置与后置两个版本号,因此.我们应该 ...

  3. C++学习笔记之运算符重载

    一.运算符重载基本知识 在前面的一篇博文 C++学习笔记之模板(1)——从函数重载到函数模板 中,介绍了函数重载的概念,定义及用法,函数重载(也被称之为函数多态)就是使用户能够定义多个名称相同但特征标 ...

  4. 《Inside C#》笔记(十一) 运算符重载

    运算符重载与之前的索引器类似,目的是为了让语言本身使用起来更方便直接,也是一种语法糖. 一 运算符重载(Operator Overloading) 运算符重载的存在,使得现有的各种运算符可以被重新定义 ...

  5. C++学习6-面向对象编程基础(运算符重载、类的派生与继承、命名空间)

    运算符重载 重载的运算符是具有特殊名字的函数:它们的名字由关键字operator和其后要定义的运算符号共同组成.重载的运算符是遵循函数重载的选择原则,根据不同类型或不同参数来选择不同的重载运算符. 运 ...

  6. lintcode-208-赋值运算符重载

    208-赋值运算符重载 实现赋值运算符重载函数,确保: 新的数据可准确地被复制 旧的数据可准确地删除/释放 可进行 A = B = C 赋值 说明 本题只适用于C++,因为 Java 和 Python ...

  7. C++学习(12)—— 运算符重载

    运算符重载概念:对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型 1.加号运算符重载 作用:实现两个自定义数据类型相加的运算 #include <iostream> #i ...

  8. 新标准C++程序设计读书笔记_运算符重载

    形式 返回值类型 operator 运算符(形参表) { …… } 运算符重载 (1)运算符重载的实质是函数重载(2)可以重载为普通函数,也可以重载为成员函数 class Complex { publ ...

  9. C#高级编程笔记2016年10月12日 运算符重载

    1.运算符重载:运算符重重载的关键是在对象上不能总是只调用方法或属性,有时还需要做一些其他工作,例如,对数值进行相加.相乘或逻辑操作等.例如,语句if(a==b).对于类,这个语句在默认状态下会比较引 ...

随机推荐

  1. POJ 2478 Farey Sequence

     名字是法雷数列其实是欧拉phi函数              Farey Sequence Time Limit: 1000MS   Memory Limit: 65536K Total Submi ...

  2. Android去掉listView,gridView等系统自带阴影

    当我们使用listView的时候,拉到顶,或是拉到底部的时候,我们会发现有系统自带的阴影效果出现,不同手机出现的颜色可能还会不一样. 在以前我始终都有注意到此问题,一直以为是系统自带的,不能去掉.也没 ...

  3. Changing Icon File Of Push Button At Runtime In Oracle Forms 6i

    Set Icon_File property in When-Mouse-Enter trigger Suppose you are creating icon based menu system i ...

  4. 向Array中添加希尔排序

    希尔排序思路 我们在第 i 次时取gap = n/(2的i次方),然后将数组分为gap组(从下标0开始,每相邻的gap个元素为一组),接下来我们对每一组进行直接插入排序. 希尔排序实现 Functio ...

  5. SQLServer 之 常用函数及查看

    一.查看 (1)应用程序名称              SELECT APP_NAME() (2)获取登录者名字           SELECT SUSER_NAME() (3)获取字段定义的长度  ...

  6. Qt 学习之路:QStringListModel

    上一章我们已经了解到有关 list.table 和 tree 三个最常用的视图类的便捷类的使用.前面也提到过,由于这些类仅仅是提供方便,功能.实现自然不如真正的 model/view 强大.从本章起, ...

  7. CentOS 安装nload(流量统计)

    yum install gcc gcc-c++ ncurses-devel wget http://www.roland-riegel.de/nload/nload-0.7.2.tar.gz tar ...

  8. [经验分享]WebApi+SwaggerUI 完美展示接口

    不喜欢说废话,直接上干货. 第一步: 打开VS IDE ,新建一个WebAPI项目 选择Web .Net FrameWork (如果喜欢使用.Net Core的可以使用.Net Core) 选择Web ...

  9. 用Java实现栈结构

    栈是一种先进后出的数据结构,出栈入栈都是操作的栈顶元素,下面是利用Java语言实现的一个简单的栈结构 class MyStack{ private int size;//栈大小 private Obj ...

  10. C# .NET 0命令行安装Windows服务程序

    设计原则:万物皆对象 背景:在我的项目中,即需要与硬件通过Socket连接通讯,又需要给App提供Wcf服务操作接口,虽然都完成了,但是却是一个控制台(虽然我很喜欢控制台,因为它简单易用),把它放到服 ...