[C++] 六 友元、运算符重载、string类相关函数

友元

类具有数据的隐藏性与封装性,被封装好的数据是通过公开接口访问的,相比于不封装直接访问属性值,执行效率一定是下降的。如果不隐藏与封装,又不符合面向对象的特性
友元函数可以在一个类封装的基础上,突破权限吗,访问到所有的属性值,且没有封装的性能开销(参数传递、类型检查、安全检查等)
友元函数的缺点就是让类的封装变得不可靠,通常只用于运算符重载
友元函数使用主要分为以下几种情况:
友元函数
友元类
友元成员函数
无论哪一种友元的用法,友元都不属于被访问数据的类中的函数

友元函数

class Test
{
private:
	int a;
public:
	Test(int a):a(a){}
	
	//“声明”友元函数
	friend void func(Test& t);
};

//类外定义友元函数
void func(Test& t)
{
	cout << ++t.a << endl;
}

友元函数没有this指针,因此需要一个对象参数
友元函数的声明可以在类中的任何位置
理论上,友元函数可以是多个类的友元函数,只需要在类中分别声明

友元类

当一个类b成为另一个类a的友元类时,那么类a中的所有成员都可以被类b访问

class A
{
private:
    int value;

public:
    A(int value):value(value){}

    // 声明友元类
    friend class B;
};

class B
{
public:
    void test(A& a)
    {
        // 尽管此函数拥有this指针
        // 但是这个this指针指向的不是A对象,而是B对象
        cout << ++a.value << endl;
    }
};

注意:
友元关系是单向的,不具有交换性
友元关系不具有传递性
友元关系不能被继承

友元成员函数

如果类b的某个成员函数可以访问类a的所有成员,那么这个成员函数就是类a的友元成员函数
友元函数的编写要注意相互依赖关系

// 3. 声明类A
class A;

class B
{
public:
    // 2. 声明成员函数
    void func(A& a);
};

class A
{
private:
    int value;

public:
    A(int value):value(value){}

    // 1. 确定友元关系:声明友元成员函数
    friend void B::func(A& a);
};

// 4. 定义友元成员函数
void B::func(A &a)
{
    cout << ++a.value << endl;
}

运算符重载

概念

函数可以重载,运算符也可以重载
C++中运算符默认操作数只能是基本数据类型,但是对于很多程序员自定义的类型,也需要类似的运算操作,这时可以把运算符看作为一个函数,对运算符进行重载,增加新的函数参数类型,使其可以处理自定义类型完成特定的操作

可以被重载的运算符
算数运算符:+、-、、/、%、++、–
位操作运算符:&、|、~、^、<<、>>
逻辑运算符:!、&&、||
比较运算符:<、>、>=、<=、==、!=
赋值运算符:=、+=、-=、
=、/=、%=、&=、|=、^=、<<=、>>=
其他运算符:[]、()、->、,、new、delete、new[]、delete[]

不能重载的运算符
成员运算符’.‘、指针运算符’*‘、三目运算符’?‘、sizeof、作用域’::’

运算符重载方式有两种:
友元函数运算符重载
成员函数运算符重载

友元函数运算符重载

无论哪种运算符重载,都要把运算符看作一为个函数

int a = 1;
int b = 2;
int c = a + b;
+:函数名称:operator +
//参数1:a
//参数2:b
//a+b返回值:a+b的结果
class Integer
{
private:
    int value;

public:
    Integer(int value):value(value){}

    int get_value() const
    {
        return value;
    }

    // 友元函数运算符重载声明
    friend Integer operator +(Integer& i1,Integer& i2);
    friend Integer operator ++(Integer& i); // 前置++
    friend Integer operator ++(Integer& i,int); // 后置++
};

Integer operator +(Integer& i1,Integer& i2)
{
    return i1.value+i2.value; // 隐式调用构造函数
}

Integer operator ++(Integer& i)
{
    return ++i.value;
}

Integer operator ++(Integer& i,int)
{
    return i.value++;
}

int main()
{
    Integer i1(1);
    Integer i2(2);

    cout << (i1++).get_value() << endl; // 1
    cout << (++i1).get_value() << endl; // 3

    Integer i3 = i1+i2;
    cout << i3.get_value() << endl; // 5

    return 0;
}

成员函数运算符重载

相对于友元函数运算符重载,成员函数运算符重载是把友元替换为成员函数,参数的数量

class Integer
{
private:
    int value;

public:
    Integer(int value):value(value){}

    int get_value() const
    {
        return value;
    }

    // 成员函数运算符重载声明
    Integer operator +(Integer& i);
    Integer operator ++(); // 前置++
    Integer operator ++(int); // 后置++
};

Integer Integer::operator +(Integer& i)
{
    // 使用this指针来代替第一个参数
    return this->value+i.value;
}

Integer Integer::operator ++()
{
    return ++this->value;
}

Integer Integer::operator ++(int)
{
    return this->value++;
}
int main()
{
    Integer i1(1);
    Integer i2(2);

    cout << (i1++).get_value() << endl; // 1
    cout << (++i1).get_value() << endl; // 3

    Integer i3 = i1+i2;
    cout << i3.get_value() << endl; // 5

    return 0;
}

成员函数运算符重载也可以声明定义不分离

Integer operator ++()
{
	return ++this->value;
}

其他情况

当我们在一个类中不写赋值运算符重载的逻辑时,编译器会自动添加赋值运算符重载函数。赋值运算符重载只支持成员函数运算符重载,不支持友元函数运算符重载

class Integer
{
private:
    int value;

public:
    Integer(int value):value(value){}

    int get_value() const
    {
        return value;
    }

    // 编译器自动添加
    Integer& operator =(const Integer& i)
    {
        this->value = i.value;
        return *this;
    }
};

编译器自动添加的赋值运算符重载函数与浅拷贝的逻辑相似,因此当出现指针类型的成员变量时,除了使用深拷贝的构造函数外,还应该重载赋值运算符

另外,类型转换运算符重载也只支持成员函数运算符重载,并且其写法比较特殊

class Integer
{
private:
	int value;
public:
	Integer(int value):value(value){}
	void set_value(int value)
	{
		this->value = value;
	}
	int get_value() const
	{
		return value;
	}
	//类型转换运算符重载函数
	operator int()
	{
		//返回值就是转换后的数据
		return value;
	}
};
int main()
{
	int i0 = 1;
	Integer i1 = i0; // 隐式调用构造函数
    cout << i1.get_value() << endl; // 1
    i1.set_value(2);
    i0 = i1; // 类型转换 Integer → int
    cout << i0 << endl; // 2

    return 0;
}

std::string类相关函数

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

using namespace std;

int main ()
{
    string s; // 生成一个空字符串
    // 判断字符串是否为空
    cout << s.empty() << endl;
    // 隐式调用构造函数
    string s1 = "abc";
    // 上面的写法等效于
    string s2("abc");
    // 判断内容是否相同
    cout << (s1 == s2) << endl;
    cout << s1.compare(s2) << endl;
    // 拷贝构造函数
    string s3(s2);
    cout << s3 << endl;

    // 参数1:char* 源字符串
    // 参数2:保留前几个字符
    string s4("ABCDEFG",2);
    cout << s4 << endl;

    s = "ABCDEFG";
    // 参数1:string 源字符串
    // 参数2:不保留前几个字符
    string s5(s,2);
    cout << s5 << endl;

    // 参数1:字符数量
    // 参数2:字符内容
    string s6(5,'A');
    cout << s6 << endl;

    // 交换
    swap(s5,s6);
    cout << s5 << " " << s6 << endl;

    // 字符串连接符
    string s7 = s5 + s6;
    cout << s7 << endl;
    cout << "aaaaa" + s7 << endl;

    // 向后追加字符串,支持链式调用
    s7.append("r78w3e").append("fjksd");
    cout << s7 << endl;

    // 向后追加单字符
    s7.push_back('U');
    cout << s7 << endl;

    // 在制定的位置插入字符串
    // 参数1:插入的位置
    // 参数2:插入的内容
    s7.insert(1,"888");
    cout << s7 << endl;

    // 删除内容
    // 参数1:删除的位置
    // 参数2:删除的字符数量
    s7.erase(1,4);
    cout << s7 << endl;

    // 替换字符串
    // 参数1:替换的起始位置
    // 参数2:替换的字符数量
    // 参数3:新替换的内容
    s7.replace(1,4,"*****");
    cout << s7 << endl;

    // 清空
    s7.clear();
    cout << s7.size() << endl;

    char c[10];

    s7 = "1234567890";
    // 参数1:拷贝到哪个字符数组中
    // 参数2:拷贝的字符数量
    // 参数3:拷贝的起始位置
    s7.copy(c,5,1);
    cout << c << endl;

    // std::string → char[] 向前兼容
    const char* cp = s7.c_str();
    cout << cp << endl;

    char c2[20];
    strcpy(c2,cp);
    cout << c2 << endl;

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值