C++学习之第七天-友元与运算符重载

一、选择题1.关于友元的描述中,(A) 是错误的。

A.友元函数是成员函数,它被说明在类体内

B.友元函数可直接访问类中的私有成员

C.友元函数破坏封装性,使用时尽量少用

D.友元类中的所有成员函数都是友元函数

2.下面对于友元函数描述正确的是(C)。
A.友元函数的实现必须在类的内部定义
B.友元函数是类的成员
C.友元函数破坏了类的封装性和隐藏性
D.友元函数不能访问类的私有成员

3.下列的各类函数中,(C)不是类的成员函数。
A. 构造函数   B. 析构函数  C. 友元函数  D. 拷贝构造函数

4.友元的作用是。(A)
A.提高程序的运行效率  B.加强类的封装性
C. 实现数据的隐蔽       D. 增加成员函数的种类

5、如果类A被说明成类B的友元,则(D,E)。(多选题)
A、类A的成员即类B的成员 
B、类B的成员即类A的成员
C、类A的成员函数不能访问类B的成员 
D、类A的成员函数可以访问类B的成员
E、类B不一定是类A的友元

二、写出下列程序的结果

#include <iostream>

using std::endl;
using std::cout;

class B 
{  
   int y;
public:
	  friend class  A; 
};
class A
{ 
      int x;
 public:  
     A(int a,B &r, int b)  
	 {
		x=a; 
		r.y=b;
	 } 
     void Display( B & ); 
};
void A::Display(B &r)
{
    cout<<x<<" "<<r.y<<endl;
}

int main( )
{   B Obj2;
    A Obj1(33,Obj2,88);//x=33,obj.y=88
    Obj1.Display(Obj2);//
	

	return 0;

} 

运行结果:

扫描二维码关注公众号,回复: 13289808 查看本文章

33 88 //B不能直接访问自己的私有变量,而A作为B类的友元可以访问。

三、简答题

1、什么是友元?友元的存在形式有?友元有何特点?

1.在类以外定义了一个函数,在类里面用friend对此函数进行声明,此函数就为本类的友元函数,友元函数可以访问该类中的私有成员。

2.友元的3种存在形式:普通函数(自由函数/全局函数),成员函数-加类作用域,友元类

3.友元的特点:1.允许访问类的私有成员 2.类内用friend+函数原型声明,类外定义 

                         3.单向且不传递,不被继承。 4.重载函数与友元不产生关联

2、什么是运算符重载?运算符重载的原则是什么?有哪些规则?不能重载的运算符有哪些?

1.什么是运算符重载?

        重载即重写赋予新的含义,对已提供的运算符进行重载,赋予它们新的含义,使之一名多用,运算符重载实质上是函数的重载。

2.运算符重载的原则。

        尽量使重载的运算符与其内值的、广为接受的语义保持一致。

3.运算符重载的规则。

        1.只能对已有的C++的运算符进行重载,不允许用户自定义新的运算符

        2.重载后的运算符,其优先级和结合性保持原固有的不变

        3.重载不能改变运算符操作对象的个数,原来有几个操作数、操作数在左还是在右,这些都不会改变。

        4.重载运算符不能有默认参数

        5.重载的运算符的操作对象必须至少有一个是自定义类型或枚举类型。

4.不能进行重载的运算符。

        1.成员访问运算符:.

        2.成员指针访问运算符:.*

        3.作用域运算符:::

        4.长度运算符:sizeof

        5.条件运算符: ?:

3.运算符重载的形式有哪几种?

1.运算符重载函数作为类的成员函数

2.运算符重载函数是个普通函数,在类中把它声明为友元函数。

两者的区别:

        1.作为成员函数,可以少写一个函数参数。       

        2.友元不是该类的成员,如果重载的是双目运算符,形参列表必须有两个参数。

4、重载自增运算符的前置形式和后置形式有什么区别?返回值类型分别是什么?

1.重载后置运算符,参数有个占位符,用于标记与前置运算符的不同

2.前置运算符返回值为对象本身*this,使用引用类型可以节省一次拷贝构造函数调用。

3.后置运算符的返回值类型不能使用引用类型,因为返回值是一个函数内创建临时对象。(引用类型作为返回值类型时,其传出变量的生命周期必须大于该函数的生命周期)

//前置++
Complex &operator++()
{
  cout << "Complex &operator++()" << endl;
  
  //++运算

  return *this;
}

// 后置++
Complex operator++(int) /*重载后置运算符,参数有个占位符,用于标记与前置运算符的不同*/
{
  cout << "Complex &operator++()" << endl;
  Complex tmp(*this);//1.先保存之前的状态
 
  //++运算		//2.进行++操作
			//3.把对象++之前的状态返回
  return tmp;//返回的是一个临时变量,为右值,在主调函数中不能对其做取地址操作
}

四、编程题1、问题描述,编写Base类使下列代码输出为1

int i=2;int j=7;
Base x(i);
Base y(j);
cout << (x+y == j - i) << endl;

#include <iostream>
using namespace std;
#include<string>

/*
1、问题描述,编写Base类使下列代码输出为1
int i=2;int j=7;
Base x(i);
Base y(j);
cout << (x+y == j - i) << endl;
*/

class Base
{
public:
	Base(int n)//构造函数
		:value(n-2)
	{
	}
	int operator+(const Base &num)//重载+号运算符
	{
		return value+num.value;
	}
private:
	int value;
};
int main()
{

	int i = 2, j = 7;
	Base x(i);
	Base y(j);
	cout << (x + y == j - i) << endl;
	system("pause");
	return EXIT_SUCCESS;
}

2、实现String类的其它运算符的重载

class String 
{
public:
	String();
	String(const char *);
	String(const String &);
	~String();
	String &operator=(const String &);
	String &operator=(const char *);

	String &operator+=(const String &);
	String &operator+=(const char *);
	
	char &operator[](std::size_t index);
	const char &operator[](std::size_t index) const;
	
	std::size_t size() const;
	const char* c_str() const;
	
	friend bool operator==(const String &, const String &);
	friend bool operator!=(const String &, const String &);
	
	friend bool operator<(const String &, const String &);
	friend bool operator>(const String &, const String &);
	friend bool operator<=(const String &, const String &);
	friend bool operator>=(const String &, const String &);
	
	friend std::ostream &operator<<(std::ostream &os, const String &s);
	friend std::istream &operator>>(std::istream &is, String &s);

private:
	char * _pstr;
};

String operator+(const String &, const String &);
String operator+(const String &, const char *);
String operator+(const char *, const String &);

提示:将上面自定义String的所有函数重新实现一下,注意有些函数是可以相互调用的,这个代码不难,但是相对来说比较繁琐,可以写一个测试一个,降低错误率。

一个一个实现,一个一个地测试:

1.主函数部分

main.cpp

#include "string.h"

void test01()
{
	String i;
	cout << i.size() << endl;

	String a("hello");//1.完成有参构造函数,获取传进来字符的长度,申请对等空间,拷贝内容

	cout << a << endl;//2.完成左移运算符进行对对象输出打印

	String b(a); //3.完成拷贝构造函数

	cout << a << endl;
	cout << b << endl;

	String c("world");
	a = c;			//4.完成对象赋值给对象运算符重载
	cout << a << endl;

	a = a;
	cout << a << endl;//允许自复制
	cout << endl;
	a = "hello world";//5.重写赋值运算符,允许直接赋值字符串
	cout << a << endl;

	a += c;		//6.重写复合运算符+=,允许用+=来拼接两个对象的字符串
	cout << a << endl;

	a += "my love";//7.重写+=,允许用+=使对象与字符串进行拼接

	cout << a << endl;
	cout << endl << endl;
	cout << a[0] << endl; //9.重写下标运算符[],允许通过下标来获取string的字符
	cout << a[22] << endl;
	cout << a.size() << endl;
	a[0] = 'o';		//允许被修改
	cout << a << endl;

	const String f("abandon");//10.重写[]运算符,使常函数的内容不允许被修改
	cout << f << endl;
	cout << f[0] << endl;
	//f[0] = 'h'; //常对象不允许被修改

	cout << endl << endl;//11.实现.c_str()函数
	cout << f.c_str() << endl;
	cout << a.c_str() << endl;

	
	
}
//关系运算符重载
void test02()
{
	//12.重载==,实现判断两个对象是否相等
	String a("hello");
	String b("world");
	String c("hello");
	if (a == b)
		cout << "a=b" << endl;
	else
		cout << "a!=b" << endl;

	if (a == c)
		cout << "a=c" << endl;
	else
		cout << "a!=c" << endl;
	cout << endl << endl;
	//13.重载 != , 实现判断两个对象是否不等
	if (a != b)
		cout << "a!=b" << endl;
	else
		cout << "a=b" << endl;

	if (a != c)
		cout << "a!=c" << endl;
	else
		cout << "a=c" << endl;

	//14~17:>,<,>=,<=
	if (a >= c)
		cout << "a>=c" << endl;

	if (a <= c)
		cout << "a<=c" << endl;


	if (b > a)
		cout << "b>a" << endl;

	if (a < b)
		cout << "a<b" << endl;
}
//重写右移输入运算符
void test03()
{
	String c1;
	cin >> c1;//输入运算符默认遇到空格符结束
	cout << c1 << endl;
}
//重载+运算符的三种情况,代码与+=类似
void test04()
{
	String c1("hello world,");
	String c2("I love C++.");
	//1.对象与对象相加进行拼接
	String c3;
	c3 = c1 + c2;
	cout << c3 << endl;
	
	cout << endl << endl;
	String c4("Hey friend,");
	//2.对象与字符串相加进行拼接
	c3 = c4 + "I love C++ and Python.";

	cout << c3 << endl;

	cout << endl << endl;
	//3.字符串与对象相加进行拼接

	c3 = "I love Python and C++," + c4;
	cout << c3 << endl;
}
void test05()
{
	String c1 = "hello";
	cout << c1 << endl;
}
int main()
{

	//test01();
	//test02();
	//test03();
	//test05();
	test04();

	system("pause");
	return EXIT_SUCCESS;
}

头文件部分

string.h

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
#include<string>

class String
{
public:
	String();//1.声明一个空string,空string默认申请一个字节的空间

	String(const char *str);//有参构造

	friend ostream &operator<<(ostream &os, const String &s);//2.左移运算符重载

	String(const String &);//3.拷贝构造函数

	~String();				//4.析构函数

	String &operator=(const String &);//5.允许对象与对象之间赋值,重新赋值运算符函数

	String &operator=(const char *);//6.重写赋值运算符,允许直接给对象赋值

	String &operator+=(const String &); //7. +=对象与对象相加拼接字符串

	String &operator+=(const char *);//8.+= 对象直接与字符串相加拼接字符串

	char &operator[](size_t index);//9.[],允许用中括号访问对象中的某个字符
	size_t size() const;
	
	const char &operator[](size_t index) const;//10,[],只允许访问,不允许修改

	
	const char* c_str() const;//11.对象调用s.c_str()函数,是个只读字符串

	friend bool operator==(const String &, const String &);//12.==,判断两个对象是否相等

	friend bool operator!=(const String &, const String &);//13.!=,判断两个对象是否不等

	//14~17:<,>,<=,>=
	friend bool operator<(const String &, const String &);
	friend bool operator>(const String &, const String &);
	friend bool operator<=(const String &, const String &);
	friend bool operator>=(const String &, const String &);

	
	friend istream &operator>>(istream &is, String &s);//18.重载输入运算符>>

	//+,重载+运算符,拼接
	friend String operator+(const String &, const String &);
	friend String operator+(const String &, const char *);
	friend String operator+(const char *, const String &);

private:
	char * _pstr;
};
//1.对象与对象相加拼接
String operator+(const String &, const String &);

//2.对象与字符串相加进行拼接
String operator+(const String &, const char *);

//3.字符串与对象相加进行拼接
String operator+(const char *, const String &);

函数实现部分

string.cpp

#include "string.h"

//1.完成无参构造函数与有参构造函数
String::String()
{
	_pstr = new char[1]();//空string默认给1字节空间
}
String::String(const char *str)//有参构造函数
	:_pstr(new char[strlen(str)+1]())
{
	//cout << "有参构造函数" << endl;
	strcpy(_pstr, str);
}
//2,完成重载左移输出运算符
ostream &operator<<(ostream &os, const String &s)
{
	os << s._pstr;

	return os;
}
//3.完成拷贝构造函数
String::String(const String &s)
{
	//cout << "拷贝构造函数" << endl;
	_pstr = new char[strlen(s._pstr) + 1]();
	strcpy(_pstr, s._pstr);
}

//4.完成析构函数
String::~String()
{
	if (_pstr)
	{
		delete[]_pstr;
		_pstr = nullptr;
	}
	//cout << "析构函数" << endl;
}
//5.允许对象与对象之间赋值,重写对象赋值运算符函数
String &String::operator=(const String &s)
{
	if (_pstr!= s._pstr)//1.自复制
	{
		delete[]_pstr;//2.释放左值
		_pstr = nullptr;

		_pstr = new char[strlen(s._pstr) + 1]();//3,申请新空间,拷贝内容
		strcpy(_pstr, s._pstr);
	}

	return *this;//4.返回自身
}
//6.重写赋值运算符,允许直接给对象赋值
String &String::operator=(const char *s)
{
	//1.释放左值
	if (_pstr)
	{
		delete[]_pstr;
		_pstr = nullptr;
	}
	_pstr = new char[strlen(s) + 1];//2.重新申请堆空间
	strcpy(_pstr, s);//3.复制内容
	return *this;//4.返回本身
}

//7. +=对象与对象相加
String &String::operator+=(const String &s)
{
	//1.记录新字符串大小
	size_t newSize = strlen(_pstr) + strlen(s._pstr) + 1;

	//2.申请一个临时堆空间,存储接起来的内容
	char *temp = new char[newSize]();

	//3.拷贝内容,直接拼接
	strcat(temp, _pstr);
	strcat(temp, s._pstr);

	//4.释放左操作数
	if (_pstr)
	{
		delete[]_pstr;
		_pstr = nullptr;
	}

	//5.建立联系
	_pstr = temp;
	temp = nullptr;//防止temp称为野指针
	return *this;
}

//8.+= 对象直接与字符串相加拼接字符串
String &String::operator+=(const char *s)
{
	//1.记录新字符串大小
	size_t newSize = strlen(_pstr) + strlen(s) + 1;

	//2.申请一个临时堆空间,存储接起来的内容
	char *temp = new char[newSize]();

	//3.拷贝内容
	strcat(temp, _pstr);
	strcat(temp, s);

	//4.释放左操作数
	if (_pstr)
	{
		delete[]_pstr;
		_pstr = nullptr;
	}

	//5.建立联系
	_pstr = temp;
	temp = nullptr;//防止temp称为野指针
	return *this;
}


//9.[],允许用中括号访问对象中的某个字符
char &String::operator[](size_t index)
{
	if (index < size())//1.下标小于字符串大小才允许返回
	{
		return _pstr[index];
	}
	else//2.下标如果大于size(),返回'\0'
	{
		static char charnull = '\0';//不可返回局部变量的引用
		return charnull;
	}
}

//10.成员常函数,只允许访问,不允许修改
const char &String::operator[](size_t index) const
{
	if (index < size())//1.下标小于字符串大小才允许返回
	{
		return _pstr[index];
	}
	else//2.下标如果大于size(),返回'\0'
	{
		static char charnull = '\0';//不可返回局部变量的引用
		return charnull;
	}
}

size_t String::size() const
{
	return strlen(_pstr);
}
//11.对象调用s.c_str()函数,是个只读字符串
const char* String::c_str() const
{
	return _pstr;
}
//12.==,判断两个对象是否相等
bool operator==(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr) == 0;
}
//13.!=,判断两个对象是否不等
bool operator!=(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr) != 0;
}
//14. <
bool operator<(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr) == -1;
}
//15.>
bool operator>(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr) == 1;
}
//16.<=
bool operator<=(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr)!=1;
}
//17.>=
bool operator>=(const String &s1, const String &s2)
{
	return strcmp(s1._pstr, s2._pstr) !=-1;
}
//18.重载输入运算符>>
istream &operator>>(istream &is, String &s)
{
	if (s._pstr)//1.先清空原堆区内容
	{
		delete[] s._pstr;
		s._pstr = nullptr;
	}
	char buf[1024];//2.弄个临时堆区,来存取从键盘输入的数据
	is >> buf;
	
	s._pstr = new char[strlen(buf) + 1]();
	strcpy(s._pstr, buf);

	return is;


}
//1.对象与对象相加进行拼接
String operator+(const String &s1, const String &s2)
{
	cout << "1.对象与对象相加拼接" << endl;
	size_t newSize = strlen(s1._pstr) + strlen(s2._pstr)+1;
	//1.记录新字符串大小

	//2.申请一个临时堆空间,存储接起来的内容
	char *temp = new char[newSize]();

	//3.拷贝内容
	strcat(temp, s1._pstr);
	strcat(temp, s2._pstr);
	
	String newstring(temp);

	delete[]temp;

	return newstring;
}

String operator+(const String &s1, const char *s2)
{
	cout << "2.对象与字符串相加拼接" << endl;
	size_t newSize = strlen(s1._pstr) + strlen(s2) + 1;
	//1.记录新字符串大小

	//2.申请一个临时堆空间,存储接起来的内容
	char *temp = new char[newSize]();

	//3.拷贝内容
	strcat(temp, s1._pstr);
	strcat(temp, s2);

	String newstring(temp);

	delete[]temp;

	return newstring;
}

String operator+(const char *s1, const String &s2)
{
	cout << "3.字符串与对象相加进行拼接" << endl;
	size_t newSize = strlen(s1) + strlen(s2._pstr) + 1;
	//1.记录新字符串大小

	//2.申请一个临时堆空间,存储接起来的内容
	char *temp = new char[newSize]();

	//3.拷贝内容
	strcat(temp, s1);
	strcat(temp, s2._pstr);

	String newstring(temp);

	delete[]temp;

	return newstring;
}

猜你喜欢

转载自blog.csdn.net/weixin_49278191/article/details/121098472