C++ day08 友元函数、函数重载和实现String类习题(有答案)

Day8

一、选择题
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的友元,则(DE)。(多选题)
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;//创建B类的的一个对象为obj2
    A Obj1(33,Obj2,88);//创建A类的一个对象,名为obj1,a为33,obj2中的x为33,b为88也就是r.y为88,类B中A的y为88
    Obj1.Display(Obj2);
	

	return 0;

} 

//33  88

三、简答题

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

友元函数友元存在形式:友元的特点
允许一个函数成为一个类的友元函数则被允许访问该类中的public、private、protected的数据成员①友元函数
②友元类
①单向的、不具备传递性、不能被继承
②优点:提高了程序的运行效率。
③缺点:破坏了类的封装性和数据的透明性。

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

运算符重载的原则规则
①为了防止用户对标准类型进行运算符重载,C++规定重载的运算符的操作对象必须至少有一个是自定义类型或枚举类型
②重载运算符之后,其优先级和结合性还是固定不变的。
③重载不会改变运算符的用法,原来有几个操作数、操作数在左边还是在右边,这些都不会改变。
④重载运算符函数不能有默认参数,否则就改变了运算符操作数的个数。
⑤重载逻辑运算符(&&,||)后,不再具备短路求值特性
⑥不能臆造一个并不存在的运算符,如@、$等

3、不能重载的运算符有哪几个?

. .* ?: :: sizeof ,总共5个

4、运算符重载的形式有哪几种?

运算符重载的形式
①采用普通函数重载
②采用成员函数重载
③采用友元函数重载

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

前置形式的自增运算符后置形式的自增运算符
形式区别如果按照通常的办法(成员函数不带参数)来重载++运算符,那么重载的就是前置版本为重载函数添加一个Int型的参数,仅用来告诉编译器这是一个运算符后置形式,实际调用不需要传递参数
返回值类型前置++返回的是对象的引用,左值后置++(没有用引用,会执行一次拷贝构造函数,而且在定义Complex类创建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 std::cout;
using std::endl;

//大写C表示类
class CBass{
    friend int operator+(const CBass &lhs,const CBass &rhs);
private:
    int _x;
public:
    //析构函数
    CBass(int x)
    :_x(x){}
};

int operator+(const CBass &lhs,const CBass &rhs){
    //return lhs._x+rhs._x;
    return -lhs._x+rhs._x;
}

int main()
{
    int i=2;
    int j=7;
    CBass x(i);
    CBass y(j);

    std::cout<< (x+y==j-i) <<std::endl;
    return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q8HkcxBy-1621142779046)(C:\Users\kachi\AppData\Roaming\Typora\typora-user-images\image-20210513220532197.png)]

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 &);

具体实现代码

#include <iostream>
#include <string>
#include <string.h>

using std::cout;
using std::endl;
//using std::string;

//大写C表示这是一个类
class CString{
private:
    char *_pstr;
public:
    //构造函数1:()表示无传入值,表示创建一个空字符串
    CString():_pstr(nullptr){}
    //构造函数2:表示传入一个字符
    CString(const char*str){
        //若传入字符串非空
        if(str){
            _pstr=new char[strlen(str)+1];
            strcpy(_pstr,str);
        }
    }
    //构造函数2:表示传入一个CString类的对象
    CString(const CString&str){
        //若传入CString类对象str的字符串非空
        if(str._pstr){
            _pstr = new char[strlen(str._pstr)+1];
            strcpy(_pstr,str._pstr);
        }
    }

    //析构函数
    ~CString(){
        if(_pstr){
            delete [] _pstr;
            _pstr=nullptr;
        }
    }

    //传入一个字符串给拷贝构造函数
    //=号重载函数
    //传入参数中有&表示修改
    //传入参数中用了&表示减少使用拷贝构造函数,增加了效率
    //函数第一个&->如果不是引用 赋值的时候就又会调用一次拷贝函数,加引用会提高效率
    //补充:(拷贝构造函数中的参数不加&会陷入死循环)
    CString &operator=(const CString&str){
        //不能自我赋值,将=号左边的字符串删除释放
        if(this != &str){
            //得先删除释放原先的内存
            delete _pstr;
            _pstr=nullptr;
        }
        //若传入对象的字符串不为空
        if(str._pstr){
            //得用深拷贝,不然当删除前一个赋值的右边的值时,左边的值将失去指向的值
            _pstr=new char[strlen(str._pstr)+1];
            strcpy(_pstr,str._pstr);
        }
        //这里的*表示解引用
        return *this;
    }

    //传入一个字符给拷贝构造函数
    CString &operator=(const char*str){
        if(str){
            _pstr=new char[strlen(str)+1];
            strcpy(_pstr,str);
        }
    }

    //传入一个字符串
    CString &operator+=(const CString &str){
        size_t len=strlen(_pstr)+strlen(str._pstr)+1;
        char *tmp=new char[len]();
        strcpy(tmp,_pstr);
        strcat(tmp,str._pstr);
        delete [] _pstr;
        _pstr=tmp;//把tmp的字符串赋给_pstr
        //返回对象的引用,为左值
        return *this;
    }

    //传入一个字符
    CString &operator+=(const char *str){
        size_t len=strlen(_pstr)+strlen(str)+1;
        char *tmp=new char[len]();
        strcpy(tmp,_pstr);
        strcat(tmp,str);
        delete [] _pstr;
        _pstr=tmp;//把tmp的字符串赋给_pstr
        //返回对象的引用,为左值
        return *this;
    }
    
    //返回字符数组里面的每一个字符
    //size_t的特点>=0
    //不加&会造成拷贝的是右值,也就是一个字母;加了引用返回的就是字符数组的实体而不是一个简单的字母
    //就可以对里面的数据进行操作
    //补充1:(&什么时候不加:要求返回的是局部数据,临时对象,尽量都加)
    //补充2:流对象尽量都加
    //重载下标访问运算符能降低越界的危险
    char &operator [](std::size_t idx){
        //len存字符串长度
        size_t len=strlen(_pstr);
        //若要求输出的字符下标符合标准,则返回相应字符
        if(idx<len){
            return _pstr[idx];
        }
        //因为这是个引用函数,所以我们要返回生命周期比函数周期大的char字符
        else{
            static char nullchar='\0';
            //若不加static,返回一个局部变量引用就会报错
            return nullchar;
        }
    }
    //前后都加const
    const char &operator [](std::size_t idx) const{
        //len存字符串长度
        size_t len=strlen(_pstr);
        //若要求输出的字符下标符合标准,则返回相应字符
        if(idx<len){
            return _pstr[idx];
        }
        //因为这是个引用函数,所以我们要返回生命周期比函数周期大的char字符
        else{
            static char nullchar='\0';
            //若不加static,返回一个局部变量引用就会报错
            return nullchar;
        }
    }

    //返回字符数组的大小,直接用对象名.size()得到字符数组的大小
    std::size_t size() const{
        return strlen(_pstr);
    }
    //返回C风格的字符串
    const char* c_str() const{
        return _pstr;
    }

    //输出流运算符不能作为成员函数,因为非静态成员函数的第一个参数是this指针,
    //而输出流运算符的第一个参数是流对象,这样就能改变操作数据位置,所以
    //输出流运算符不能以成员函数重载,但可以以友元函数重载
    friend std::ostream &operator<<(std::ostream&os , const CString&str){
        os<<str._pstr;
        return os;
    }
    friend std::istream &operator>>(std::istream &is,CString &str){
        CString tmp;
        is>>tmp;
        if(str._pstr){
            delete [] str._pstr;
            str._pstr=nullptr;
        }
        str._pstr = new char[tmp.size()+1];
        //把C风格字符串赋给str的_pstr空字符串
        strcpy(str._pstr,tmp.c_str());
        return is;
    }
    friend bool operator==(const CString&,const CString&);
    friend bool operator!=(const CString&,const CString&);
    friend bool operator>(const CString&,const CString&);
    friend bool operator<(const CString&,const CString&);
    friend bool operator<=(const CString&,const CString&);
    friend bool operator>=(const CString&,const CString&);
};

CString operator+(const CString&lhs,const CString & rhs){
    CString tmp = lhs;
    return tmp+=rhs;
}
CString operator+(const CString&lhs,const char*rhs){
    CString tmp=lhs;
    return tmp+rhs;
}
CString operator+(const char*rhs,const CString&lhs){
    CString tmp=lhs;
    return tmp+=rhs;
}

bool operator==(const CString&lhs,const CString&rhs){
    //若相同返回0,!0表示1
    return !strcmp(lhs._pstr,rhs._pstr);
}
bool operator!=(const CString&lhs,const CString&rhs){
    return !(lhs==rhs);
}
bool operator<(const CString&lhs,const CString&rhs){
    return !(lhs>=rhs);
}
bool operator>(const CString&lhs,const CString&rhs){
    return !(lhs<=rhs);
}
bool operator<=(const CString&lhs,const CString&rhs){
    return strcmp(lhs._pstr,rhs._pstr)<=0;
}
bool operator>=(const CString&lhs,const CString&rhs){
    return strcmp(lhs._pstr,rhs._pstr)>=0;
}


int main()
{
    CString str1("warcraft");
    CString str2(str1);
    CString str3("buster");
    CString str4(str3);

    //
    cout<<"先输出字符串"<<endl;
    cout<<"str1="<<str1<<endl;
    cout<<"str2="<<str2<<endl;
    cout<<"str3="<<str3<<endl;
    cout<<"str4="<<str4<<endl;
    cout<<endl;

    //
    cout<<"再判断字符串"<<endl;
    cout<<"(str1==str2)="<<(str1==str2)<<endl;
    cout<<"(str1==str3)="<<(str1==str3)<<endl;
    cout<<"(str1<=str2)="<<(str1<=str2)<<endl;
    cout<<"(str1>str2)="<<(str1>str2)<<endl;
    cout<<endl;

    //
    CString str5;
    str5=str1;
    cout<<"str5=str1,str5="<<str5<<endl;
    cout<<endl;

 
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值