您的位置:首页 > 编程语言 > C语言/C++

C++基础学习笔记----第十二课(操作符重载-上)

2013-12-07 19:30 567 查看

本节主要讲的是C++函数标注库的定义和常见的使用方法以及程序中的全局函数进行操作符重载。

C++标准库

C++标准库和C语言标准库的定义有很多类似之处(仅仅局限于定义)。C++标准库并不是C++语言的一部分C++标准库是由C++语言编写而成的类库和函数的集合C++标准库中定义的类和对象都位于std命名空间中,这样可以防止标准库中的类和对象与其他厂商的类和对象发生冲突。

标准库的基本格式:①C++标准库下的头文件都不带.h后缀C++标准库涵盖了C库的功能

C++标准库中使用C库:C库中的<name.h>头文件转换为<cname>

C++标准库预定义了多数常用的数据结构(想起了某培训机构老师当时讲标准库了~~~)。

基本使用例程(标准库下的hello world):

#include <cstdio>
using namespace std;

int main()
{
printf("hello world\n");
return 0;
}在C++标准库中,iostream是用于表示输入输出的头文件。
表示向屏幕显示的对象count,表示通过键盘输入的对象cin。用法如下所示:

cout<<"hellot world";上面的语句代表将helloworld这个字符串左移到count这个对象中。
endl在C++标准库中是一个标示符,代表回车。

例程:

#include <iostream>
using namespace std;

int main()
{
cout<<"hellot world"<<endl;
return 0;
}
实际上已经进行了一次运算符的重载,因为<<左移运算符是不能够将字符串左移的,但是这里左移运算符的作用是将字符串hello world左移到cout这个对象里,然后再屏幕上进行显示。

操作符重载

操作符重载的主要作用是使运算符在不同的上下文有不同的语义。

在C语言中不能够将两个结构体直接进行相加,在C++同样也是。

A a1 = {1,2};
A a2 = {3,4};

A a3 = a1 + a2;复数相加的实现(采用函数调用的方式):
#include <iostream>

using namespace std;

struct A
{
int a;
int b;
};

/*这里定义一个全局函数add,函数的返回类型是A,这样可以直接通过函数的返回值来实现两个类中的成员完成相加*/
A add(A& a1, A& a2)
{
A ret;
ret.a = a1.a + a2.a;
ret.b = a1.b + a2.b;

return ret;
}

int main()
{
A a1 = {1,2};
A a2 = {3,4};

A a3 = add(a1,a2);

cout<<a3.a<<endl;
cout<<a3.b<<endl;

return 0;
}

操作符重载的基本方法

①使用operator关键字进行函数扩展操作符,operator加上具体的操作符可以等价于一个函数名来使用的。②operator的本质是通过函数的重载来实现操作符的重载。在上面的程序中可以直接将add函数名替换成为operator+,这样实际上就是一种操作符重载的规则。

#include <iostream>

using namespace std;

struct A
{
int a;
int b;
};

A operator+(A& a1, A& a2)
{
A ret;
ret.a = a1.a + a2.a;
ret.b = a1.b + a2.b;

return ret;
}

int main()
{
A a1 = {1,2};
A a2 = {3,4};

/*
操作符+被重载之后已经改变了原来的意义,这里的+实际上通过A operator+这个函数来完成
所以程序这个时候可以编译通过。
*/
A a3 = a1 + a2;

cout<<a3.a<<endl;
cout<<a3.b<<endl;

return 0;
}

operator关键字操作符的扩展用于类

在上面的程序中如果将结构体扩展为一个完整的类,这个时候假如将成员变量a,b定义成为private属性的,那么我们将无法实现下面的代码:

ret.a = a1.a + a2.a;
ret.b = a1.b + a2.b;使用C++中的友元解决上述问题。

C++中类的友元

基本概念:private声明使得类的成员不能被外界访问。通过friend关键字可以例外的开放private的成员的权限。

例程:

#include <iostream>

using namespace std;

struct A
{
/*这里将a,b这两个变量的属性限制为private,这样类外的函数将无法访问*/
private:
int a;
int b;
public:
A(int a = 0, int b = 0)
{
this->a = a;
this->b = b;
}
/*定义友元函数,标示operator这个函数可以调用A类中的私有成员*/
friend A operator+(A& a1, A& a2);
};

A operator+(A& a1, A& a2)
{
A ret(0,0);
ret.a = a1.a + a2.a;
ret.b = a1.b + a2.b;

return ret;
}

int main()
{
A a1 = (1,2);
A a2 = (3,4);

A a3 = a1 + a2;

/*cout<<a3.a<<endl;
cout<<a3.b<<endl;*/

return 0;
}
注意:类的友元的声明位置一般都在一个类的结尾的位置,如果将一个类的友元声明在类的开始位置或者其他位置程序是可以编译通过的,但是可能会导致其他的问题,因为类的友元实际上是类似于一个“函数的调用”,所以如果类的友元声明的太靠前,那么一部分类的成员变量可能并不是我们想要的值。
上述程序的注释可以通过在A类中声明main()函数的friend来进行解决:

不过这样的方法存在很多问题,因为将main()函数声明为类A的友元,那么其实就是相当于把类A中的所有成员都变成了public的了,这样其实失去了意义。

friend int main();

左移操作符(<<)的重载

程序如下:

#include <iostream>

using namespace std;

struct A
{
/*这里将a,b这两个变量的属性限制为private,这样类外的函数将无法访问*/
private:
int a;
int b;
public:
A(int a, int b)
{
this->a = a;
this->b = b;
}

/*定义友元函数,标示operator这个函数可以调用A类中的私有成员*/
friend A operator+(A& a1, A& a2);

/*friend int main();*/

friend ostream& operator<< (ostream& out, const A& d);
};

A operator+(A& a1, A& a2)
{
A ret(0,0);
ret.a = a1.a + a2.a;
ret.b = a1.b + a2.b;

return ret;
}

ostream& operator<< (ostream& out, const A& d)
{
out<<d.a<<"+"<<d.b<<"i"<<endl;
return out;
}

int main()
{
A a1 = A(1,2);
A a2 = A(3,4);

A a3 = a1 + a2;

/*cout<<a1.a;
cout<<a1.b;*/
cout<<a1<<endl;
cout<<a2<<endl;
cout<<a3<<endl;

return 0;
}程序的主要部分如下:
ostream& operator<< (ostream& out, const A& d)
{
out<<d.a<<"+"<<d.b<<"i"<<endl;
return out;
}
这里定义了一个ostream类型的参数,这里的ostream是输出函数的类型同时传递了两个参数ostream& out,这是一个ostream类型的引用。这里的out是一ostream类型,所以out这个变量具有ostream这个类的特性,所以可以直接进行<<字符串等一系列操作了。
这里将operator这个函数定义为ostream这个类型而不定义成为void类型,如果在这里定义为void类型,那么主函数中的cout<<a3可以成功打印,而cout<<a3<<endl打印就编译不过因为这里的cout<<a3的实际可以转换为operator<<(out,a3),这个时候函数返回的类型是void,那么是不可以将endl再输入到一个void类型中了。这个叫做C++重载的左移操作符支持链式调用。


程序的打印结果如下图所示:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: