【C/C++学院】(8)全局函数和类成员函数转化/友元/操作符重载

简介: <h1><span style="font-family:'Microsoft YaHei UI','Microsoft YaHei',SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif,'Microsoft YaHei',Georgia,Helvetica,Arial,sans-serif,宋体,PMingLiU,serif; font-size:

1.全局函数和类成员函数转化

    全局函数和成员函数的相互转化:只需要修改一个指向本类的this指针;

#include <iostream>
using namespace std;

class Test
{
public:
	Test(int a, int b)
	{
		this->a = a;
		this->b = b;
	}
	//成员函数
	Test &Gadd2(Test &t2)
	{
		this->a = this->a + t2.a;
		this->b = this->b + t2.b;
		return *this;
	}
public:
	int a;
	int b;
};
//全局函数
Test &Gadd1(Test &t1, Test &t2)
{
	Test t3(0, 0);
	t3.a = t1.a + t2.a;
	t3.b = t1.b + t2.b;
	return t3;
}

//从成员函数转化为全局函数 只需要加一个 this指针(指向本类的类指针)
//从全局函数转化为类的成员函数是,需要减一个做左操作数参数
void main()
{
	Test t1(1, 2), t2(3, 4);
	//Test t3 = Gadd1(t1, t2);
	t1.Gadd2(t2);

	system("pause");
}

2.友元

2.1友元函数

#include "iostream"
using namespace std;
class Test2
{
public:
    //友元函数的特点是:有一个参数是友元类的指针或引用
    friend int OpMem(Test2 *p, int a); //友元函数
    Test2(int a, int b)
    {
        this->a = a;
        this->b = b;
    }
    int getA()
    {
        return this->a;
    }
protected:
private:
    int a;
    int b;
};
int OpMem(Test2 *p, int a)
{
    p->a = a;
    return 0;
}
void main()
{
    Test2 t1(1, 2);
    t1.getA();//没有friend的情况下,如果获取对象t1的私有数据,需要用get方法。
    OpMem(&t1, 10);
    system("pause");
}

2.2友元类

#include <iostream>
using namespace std;

class A
{
	friend class B;//B是A的友元类
public:
	void  Display() { cout << x << endl; };
private:
	int  x;
};
//设计模式中的组合场景。表象是设置b100, 本质上是修改a的数据。
class  B
{
public:
	void Set(int i) { Aobject.x = i; }
	void Display()  { Aobject.Display(); }
private:
	A  Aobject;
};

void main()
{
	B  Bobject;
	Bobject.Set(100);
	Bobject.Display();
	system("pause");
}


3.操作符重载

C++有许多内置的数据类型,包括int,char,double等,每一种类型都有许多运算符,例如加,减,乘,除等。当用户定义了类的对象时,两个对象之间是不能进行这些操作的,比如hyong类的对象a+b,这样的语句如果没有重载+运算符就会出错。但C++允许用户把这些运算符添加到自已的类中以方便类对象之间的运算就像内置类型的运算一样方便,比如对象a+b这样就很明白更容易懂,当然也可以在类中定义一个对象间相加的函数,比如a.add(b)调用函数add()以实现两个对象a和b相加,但是这条语句没有比a+b更容易让人理解。

3.1通过友元函数实现操作符重载,

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;
    c3.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    ++c2;
    
    c2.print();
    
    system("pause");
}

3.2通过类的成员函数实现操作符重载

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现+操作
    friend Fushu operator+(Fushu &c1, Fushu &c2);
public:
    //通过类的成员函数实现-操作
    Fushu operator-(Fushu &c2)
    {
        Fushu tmp;
        tmp.a = this->a - c2.a;
        tmp.b = b - c2.b;//此处的this可以省略
        return tmp;
    }
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
};
Fushu operator+(Fushu &c1, Fushu &c2)
{
    Fushu tmp;
    tmp.a = c1.a + c2.a;
    tmp.b = c1.b + c2.b;
    return tmp;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    Fushu c3 = c1+c2;//operator+(c1,c2);
    c3.print();
//目标 通过类的成员函数,完成操作符重载
//1 要承认操作符重载是一个函数,要写函数原型
//2 写出函数调用语言 c1.operator-(c2)
//3 完善函数原型   
    Fushu c4 = c1 - c2;//operator-(c1,c2) -->c1.operator-(c2)-->Fushu operator-(Fushu &c2);
    c4.print();
    system("pause");
}

#include <iostream>
using namespace std;
class Fushu
{
private:
    int a;
    int b;
    //通过友元函数实现前++操作
    friend Fushu &operator++(Fushu &c2);
public:
    Fushu(int a=0, int b=0)
    {
        this->a = a;
        this->b = b;
    }
    void print()
    {
        cout << a << "+" << b << "i" << endl;
    }
public://通过类的成员函数实现前--操作
    Fushu& operator--()
    {
        this->a--;
        this->b--;
        return *this;
    }
};
Fushu &operator++(Fushu &c2)
{
    c2.a++;
    c2.b++;
    return c2;
}
void main()
{
    Fushu c1(1, 2), c2(3, 4);
    //通过友元函数实现前++操作
    ++c2;    
    c2.print();
    //通过类的成员函数实现前--操作
    --c2;    
    c2.print();
    system("pause");
}

综合:

#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	//通过友元函数实现前++操作
	friend Fushu &operator++(Fushu &c2);
	//通过友元函数实现后++操作
	friend Fushu operator++(Fushu &c2, int);//用缺省参数占位,跟前++区分
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
};

Fushu &operator++(Fushu &c2)
{
	c2.a++;
	c2.b++;
	return c2;
}

Fushu operator++(Fushu &c2, int)
{
	Fushu tmp;
	tmp = c2;
	c2.a++;
	c2.b++;
	return tmp;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	//通过友元函数实现前++操作
	++c2;	
	c2.print();
	//通过类的成员函数实现前--操作
	--c2;	
	c2.print();
	//通过友元函数实现后++操作
	c2++;
	c2.print();
	//通过类的成员函数实现后--操作
	c2--;
	c2.print();

	system("pause");
}


3.3操作符重载的正规写法

      通过友元函数可以获取友元类的私有属性,相当于获取了程序的一个后门。
#include <iostream>
using namespace std;

class Fushu
{
private:
	int a;
	int b;
	friend ostream& operator<<(ostream &cout, Fushu &c);
public:
	Fushu(int a=0, int b=0)
	{
		this->a = a;
		this->b = b;
	}
	void print()
	{
		cout << a << "+" << b << "i" << endl;
	}
public:
	//通过类的成员函数实现前++操作
	Fushu &operator++()
	{
		this->a++;
		this->b++;
		return *this;
	}
	//通过类的成员函数实现前--操作
	Fushu& operator--()
	{
		this->a--;
		this->b--;
		return *this;
	}
	//通过类的成员函数实现后--操作
	Fushu operator--(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a--;
		this->b--;
		return tmp;
	}
	//通过类的成员函数实现后++操作
	Fushu operator++(int)//用缺省参数占位,跟后--区分
	{
		Fushu tmp;
		tmp = *this;
		this->a++;
		this->b++;
		return tmp;
	}
};

ostream& operator<<(ostream &co, Fushu &c)
{
	cout << "我是复数:" << endl;
	cout << c.a << "+" << c.b << "i" << endl;
	return co;
}

void main()
{
	Fushu c1(1, 2), c2(3, 4);
	++c2;	
	c2.print();

	--c2;	
	c2.print();

	c2++;
	c2.print();

	c2--;
	c2.print();

	cout << 1 << endl;
	cout << "hello" << endl;
	//函数返回值当左值的时候,需要返回一个对象的引用, 实现链式编程
	cout << c2 << "连续" << endl;
	//没有方法去在cout类里面添加函数operator<<,只能通过全局函数实现。
	//cout.operator<<( c1);
	//void operator<<(ostream &out, Complex &c1)

	system("pause");
}

3.4操作符重载在项目中的应用:

基本的数组框架
Array.h
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_

class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
};

#endif
Array.cpp
//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}
//ArrayTest.cpp
//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		a1.setData(i, i);  //a[i] = 1;
	}

	for (int i = 0; i<a1.length(); i++)
	{
		printf("array %d: %d\n", i, a1.getData(i));
		// printf("array %d: %d\n", i, a1[i]));
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		printf("array %d: %d\n", i, a2.getData(i));
	}
	system("pause");
	return 0;
}

重载[]  =  ==  !=操作符后的代码:
//Array.h
#ifndef _ARRAY_H_
#define _ARRAY_H_
#include <string.h>
class Array
{
private:
	int mLength;//数组的长度
	int* mSpace;//内存空间

public:
	Array(int length);
	Array(const Array& obj);//copy构造函数
	int length();//取得数组长度
	void setData(int index, int value);
	int getData(int index);
	~Array();
public:
	int & operator[](int i);
	void operator=(Array &a2);
	bool operator==(Array &a1);
	bool operator!=(Array &a1);
};

#endif

//Array.cpp
#include "Array.h"

Array::Array(int length)
{
	if (length < 0)
	{
		length = 0;
	}
	mLength = length;
	mSpace = new int[mLength];
}
Array::Array(const Array& obj)
{
	mLength = obj.mLength;
	mSpace = new int[mLength];
	for (int i = 0; i<mLength; i++)
	{
		mSpace[i] = obj.mSpace[i];
	}
}
int Array::length()
{
	return mLength;
}
void Array::setData(int index, int value)
{
	mSpace[index] = value;
}
int Array::getData(int index)
{
	return mSpace[index];
}
Array::~Array()
{
	mLength = -1;
	delete[] mSpace;
}

int& Array::operator[](int i)
{
	return this->mSpace[i];
}

void Array::operator = (Array &a2)
{
	if (this->mSpace != NULL)
	{
		delete[] mSpace;
	}	
	mLength = a2.mLength;
	mSpace = new int[mLength];
    memcpy(mSpace, a2.mSpace, mLength);
}

bool Array::operator==(Array &a1)
{
	//先比较长度
	if (mLength != a1.mLength)
	{
		return false;
	}
	//比较内容
	for (int i = 0; i < a1.mLength; i++)
	{
		if (a1[i] != mSpace[i])
		{
			return false;
		}
	}
	return true;
}
//利用相等判断不等 
bool Array::operator!=(Array &a1)
{
	return !(a1 == *this);
}

//ArrayTest.cpp
#include "Array.h"
#include <iostream>
using namespace std;

int main()
{
	Array a1(10);

	for (int i = 0; i<a1.length(); i++)
	{
		//a1.setData(i, i);  
		a1[i] = i;
	}
	
	for (int i = 0; i<a1.length(); i++)
	{
		//printf("array %d: %d\n", i, a1.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a2 = a1;
	for (int i = 0; i<a2.length(); i++)
	{
		//printf("array %d: %d\n", i, a2.getData(i));
		printf("array %d: %d\n", i, a1[i]);
	}

	Array a3(10);
	a3 = a2; //执行=操作
	
	if (a2 == a1)
	{
		printf("相等");
	}
	else
	{
		printf("不相等");
	}
	system("pause");
	return 0;
}







目录
相关文章
|
5天前
|
设计模式 安全 编译器
【C++11】特殊类设计
【C++11】特殊类设计
24 10
|
10天前
|
C++
C++友元函数和友元类的使用
C++中的友元(friend)是一种机制,允许类或函数访问其他类的私有成员,以实现数据共享或特殊功能。友元分为两类:类友元和函数友元。类友元允许一个类访问另一个类的私有数据,而函数友元是非成员函数,可以直接访问类的私有成员。虽然提供了便利,但友元破坏了封装性,应谨慎使用。
40 9
|
5天前
|
存储 编译器 C语言
【C++基础 】类和对象(上)
【C++基础 】类和对象(上)
|
7天前
|
编译器 数据安全/隐私保护 C++
C++一分钟之-属性友元与访问控制
【7月更文挑战第9天】C++中的友元机制允许非成员函数或类访问私有和保护成员,打破了封装性。友元需在类内声明,常见的错误包括忘记声明、过度使用及误解友元的非继承性。要避免错误,应明确声明友元,限制其使用,并理解其局限。示例展示了如何声明和使用友元函数来访问私有数据。谨慎使用友元以保持代码的健壮性和可维护性。
13 1
|
13天前
|
C++
【C++】string类的使用④(常量成员Member constants)
C++ `std::string` 的 `find_first_of`, `find_last_of`, `find_first_not_of`, `find_last_not_of` 函数分别用于从不同方向查找目标字符或子串。它们都返回匹配位置,未找到则返回 `npos`。`substr` 用于提取子字符串,`compare` 则提供更灵活的字符串比较。`npos` 是一个表示最大值的常量,用于标记未找到匹配的情况。示例代码展示了这些函数的实际应用,如替换元音、分割路径、查找非字母字符等。
|
13天前
|
编译器 C++
【C++】string类的使用④(字符串操作String operations )
这篇博客探讨了C++ STL中`std::string`的几个关键操作,如`c_str()`和`data()`,它们分别返回指向字符串的const char*指针,前者保证以&#39;\0&#39;结尾,后者不保证。`get_allocator()`返回内存分配器,通常不直接使用。`copy()`函数用于将字符串部分复制到字符数组,不添加&#39;\0&#39;。`find()`和`rfind()`用于向前和向后搜索子串或字符。`npos`是string类中的一个常量,表示找不到匹配项时的返回值。博客通过实例展示了这些函数的用法。
|
13天前
|
存储 C++
【C++】string类的使用③(非成员函数重载Non-member function overloads)
这篇文章探讨了C++中`std::string`的`replace`和`swap`函数以及非成员函数重载。`replace`提供了多种方式替换字符串中的部分内容,包括使用字符串、子串、字符、字符数组和填充字符。`swap`函数用于交换两个`string`对象的内容,成员函数版本效率更高。非成员函数重载包括`operator+`实现字符串连接,关系运算符(如`==`, `&lt;`等)用于比较字符串,以及`swap`非成员函数。此外,还介绍了`getline`函数,用于按指定分隔符从输入流中读取字符串。文章强调了非成员函数在特定情况下的作用,并给出了多个示例代码。
|
18天前
|
C++
【C++】日期类Date(详解)②
- `-=`通过复用`+=`实现,`Date operator-(int day)`则通过创建副本并调用`-=`。 - 前置`++`和后置`++`同样使用重载,类似地,前置`--`和后置`--`也复用了`+=`和`-=1`。 - 比较运算符重载如`&gt;`, `==`, `&lt;`, `&lt;=`, `!=`,通常只需实现两个,其他可通过复合逻辑得出。 - `Date`减`Date`返回天数,通过迭代较小日期直到与较大日期相等,记录步数和符号。 ``` 这是236个字符的摘要,符合240字符以内的要求,涵盖了日期类中运算符重载的主要实现。
|
13天前
|
C++
C++】string类的使用③(修改器Modifiers)
这篇博客探讨了C++ STL中`string`类的修改器和非成员函数重载。文章介绍了`operator+=`用于在字符串末尾追加内容,并展示了不同重载形式。`append`函数提供了更多追加选项,包括子串、字符数组、单个字符等。`push_back`和`pop_back`分别用于在末尾添加和移除一个字符。`assign`用于替换字符串内容,而`insert`允许在任意位置插入字符串或字符。最后,`erase`函数用于删除字符串中的部分内容。每个函数都配以代码示例和说明。
|
13天前
|
安全 编译器 C++
【C++】string类的使用②(元素获取Element access)
```markdown 探索C++ `string`方法:`clear()`保持容量不变使字符串变空;`empty()`检查长度是否为0;C++11的`shrink_to_fit()`尝试减少容量。`operator[]`和`at()`安全访问元素,越界时`at()`抛异常。`back()`和`front()`分别访问首尾元素。了解这些,轻松操作字符串!💡 ```