【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;
}







目录
相关文章
|
3天前
|
安全 C++
【c++】继承(继承的定义格式、赋值兼容转换、多继承、派生类默认成员函数规则、继承与友元、继承与静态成员)
本文深入探讨了C++中的继承机制,作为面向对象编程(OOP)的核心特性之一。继承通过允许派生类扩展基类的属性和方法,极大促进了代码复用,增强了代码的可维护性和可扩展性。文章详细介绍了继承的基本概念、定义格式、继承方式(public、protected、private)、赋值兼容转换、作用域问题、默认成员函数规则、继承与友元、静态成员、多继承及菱形继承问题,并对比了继承与组合的优缺点。最后总结指出,虽然继承提高了代码灵活性和复用率,但也带来了耦合度高的问题,建议在“has-a”和“is-a”关系同时存在时优先使用组合。
29 6
|
21天前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
21天前
|
安全 编译器 C语言
【C++篇】深度解析类与对象(中)
在上一篇博客中,我们学习了C++类与对象的基础内容。这一次,我们将深入探讨C++类的关键特性,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载、以及取地址运算符的重载。这些内容是理解面向对象编程的关键,也帮助我们更好地掌握C++内存管理的细节和编码的高级技巧。
|
21天前
|
存储 程序员 C语言
【C++篇】深度解析类与对象(上)
在C++中,类和对象是面向对象编程的基础组成部分。通过类,程序员可以对现实世界的实体进行模拟和抽象。类的基本概念包括成员变量、成员函数、访问控制等。本篇博客将介绍C++类与对象的基础知识,为后续学习打下良好的基础。
|
24天前
|
编译器 C语言 C++
类和对象的简述(c++篇)
类和对象的简述(c++篇)
|
2月前
|
C++ 芯片
【C++面向对象——类与对象】Computer类(头歌实践教学平台习题)【合集】
声明一个简单的Computer类,含有数据成员芯片(cpu)、内存(ram)、光驱(cdrom)等等,以及两个公有成员函数run、stop。只能在类的内部访问。这是一种数据隐藏的机制,用于保护类的数据不被外部随意修改。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。成员可以在派生类(继承该类的子类)中访问。成员,在类的外部不能直接访问。可以在类的外部直接访问。为了完成本关任务,你需要掌握。
81 19
|
2月前
|
存储 编译器 数据安全/隐私保护
【C++面向对象——类与对象】CPU类(头歌实践教学平台习题)【合集】
声明一个CPU类,包含等级(rank)、频率(frequency)、电压(voltage)等属性,以及两个公有成员函数run、stop。根据提示,在右侧编辑器补充代码,平台会对你编写的代码进行测试。​ 相关知识 类的声明和使用。 类的声明和对象的声明。 构造函数和析构函数的执行。 一、类的声明和使用 1.类的声明基础 在C++中,类是创建对象的蓝图。类的声明定义了类的成员,包括数据成员(变量)和成员函数(方法)。一个简单的类声明示例如下: classMyClass{ public: int
68 13
|
2月前
|
编译器 数据安全/隐私保护 C++
【C++面向对象——继承与派生】派生类的应用(头歌实践教学平台习题)【合集】
本实验旨在学习类的继承关系、不同继承方式下的访问控制及利用虚基类解决二义性问题。主要内容包括: 1. **类的继承关系基础概念**:介绍继承的定义及声明派生类的语法。 2. **不同继承方式下对基类成员的访问控制**:详细说明`public`、`private`和`protected`继承方式对基类成员的访问权限影响。 3. **利用虚基类解决二义性问题**:解释多继承中可能出现的二义性及其解决方案——虚基类。 实验任务要求从`people`类派生出`student`、`teacher`、`graduate`和`TA`类,添加特定属性并测试这些类的功能。最终通过创建教师和助教实例,验证代码
63 5
|
2月前
|
存储 算法 搜索推荐
【C++面向对象——群体类和群体数据的组织】实现含排序功能的数组类(头歌实践教学平台习题)【合集】
1. **相关排序和查找算法的原理**:介绍直接插入排序、直接选择排序、冒泡排序和顺序查找的基本原理及其实现代码。 2. **C++ 类与成员函数的定义**:讲解如何定义`Array`类,包括类的声明和实现,以及成员函数的定义与调用。 3. **数组作为类的成员变量的处理**:探讨内存管理和正确访问数组元素的方法,确保在类中正确使用动态分配的数组。 4. **函数参数传递与返回值处理**:解释排序和查找函数的参数传递方式及返回值处理,确保函数功能正确实现。 通过掌握这些知识,可以顺利地将排序和查找算法封装到`Array`类中,并进行测试验证。编程要求是在右侧编辑器补充代码以实现三种排序算法
48 5
|
2月前
|
Serverless 编译器 C++
【C++面向对象——类的多态性与虚函数】计算图像面积(头歌实践教学平台习题)【合集】
本任务要求设计一个矩形类、圆形类和图形基类,计算并输出相应图形面积。相关知识点包括纯虚函数和抽象类的使用。 **目录:** - 任务描述 - 相关知识 - 纯虚函数 - 特点 - 使用场景 - 作用 - 注意事项 - 相关概念对比 - 抽象类的使用 - 定义与概念 - 使用场景 - 编程要求 - 测试说明 - 通关代码 - 测试结果 **任务概述:** 1. **图形基类(Shape)**:包含纯虚函数 `void PrintArea()`。 2. **矩形类(Rectangle)**:继承 Shape 类,重写 `Print
58 4