C++-友元-string字符串类

2024-01-02 09:42:41

1、友元

1.1?概念

类实现了数据的隐藏和封装,类的数据一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义为公有的,则破坏了类的封装性。但是某些情况下,需要频繁的读写类的成员函数,特别是在对成员函数多次调用时,由于参数的传递,类型检查和安全性检查等都需要时间开销,从而影响到程序的运行效率。

友元是一种定义在类外部的“普通函数”,但他还需要再类内进行声明,为了和该类的成员函数加以却别,再声明前面加一个关键字friend。友元函数不是成员函数,但是可以访问到类中的私有成员。

在于提高程序的运行效率,但是他破坏了类的封装性和隐藏性。使得非成员函数能够访问到类中私有成员。导致程序的维护性和安全性变差,因此使用友元要谨慎。

友元有三种实现方式:

  • 友元函数你p
  • 友元类
  • 友元成员函数

1.2?友元函数

友元函数不属于任何一个类,是一个类外的函数,但是在类内进行“声明”。虽然友元函数不是类中的函数,但是却可以访问类中的所有成员(包括私有成员)。

#include?<iostream>
using namespace?std;
class Test
{
private:
    int?a;//私有成员变量
public:
   Test(int?a):a(a){}
   void show()
   {
???????cout<<a<<"?"<<&a<<endl;
   }
   friend void and_test(Test?&t);//友元函数声明
};
void and_test(Test?&t)//友元函数本体
{
????cout<<t.a<<"?"<<&t.a<<endl;
}
int main()
{
????Test?t1(1);
    and_test(t1);
????t1.show();//调用类内成员函数
    return 0;
}

友元函数的使用需要注意以下几点:

  • 友元函数没有this指针
  • 友元函数的“声明”可以放置到类中任意的位置,不受权限修饰符的影响。
  • 一个友元函数理论上可以访问多个类,只需要在各个类中进行“声明”。

1.3?友元类

当一个类B成为了另一个Test的友元时,类Test的所有成员都可以被类B访问,此时类B就是类Test的友元类。

#include?<iostream>
using namespace?std;
class Test
{
    //?友元函数,类内声明
    friend void and_test(Test?&t);
    int?a;
public:
    Test(int?a):a(a){}

    void show()
    {
????????cout?<<?a?<< "?" << &a?<<?endl;
    }
    //?友元类,类内声明
    friend class B;
};
class B
{
public:
    void and_test(Test?&t)
    {
????????cout?<<?t.a?<< "?" << &t.a?<<?endl;
    }
};
int main()
{
????Test?t1(1);
????t1.show();

????B?b;
????b.and_test(t1);
    return 0;
}

友元类的使用也需要注意以下几点:

  • 友元关系不能被继承。
  • 友元关系不具有交换性(比如:类B声明称类Test的友元,类B可以访问类Test中的成员,但是类Test不能访问类B中的私有成员,如果需要访问,需要将类Test声明称类B的友元)

互为友元代码。需要类内声明,类外实现

#include?<iostream>
#include?<string.h>
using namespace?std;
class B;
class Test
{
private:
    int?a;
public:
    Test(int?i):a(i){}

    void show()
    {
????????cout?<<?a?<< "?" << &a?<<?endl;
    }
    void test(B?&b);

    //?友元类?类内声明
    friend class B;

};
class B
{
private:
    int?b?= 20;

public:
    void show(Test?&t);
    friend class Test;
};
void Test::test(B?&b)
{
????cout?<<?b.b?<<?endl;
}
void B::show(Test?&t)
{
????cout?<< ++t.a?<< "?" << &t.a?<<?endl;
}
int main()
{
????Test?t1(2);
????B?b;
????b.show(t1); //?3?0x61fe8c
????t1.show();  //?3?0x61fe8c
????t1.test(b);

    return 0;
}

1.4?友元成员函数

使类B中的成员函数成为类Test的友元成员函数,这样类B的该成员函数就可以访问类Test的所有成员。

#include?<iostream>
using namespace?std;
//?第四步:声明被访问的类
class Test;
class B
{
public:
    //?第二步:声明友元成员函数(类内声明,类外实现)
    void and_test(Test?&t);
};
class Test
{
    int?a;
public:
    Test(int?a):a(a){}
    void show()
    {
????????cout?<<?a?<< "?" << &a?<<?endl;
    }
    //?友元成员函数,第一步:确定友元函数的格式并声明
    friend void B::and_test(Test?&t);
};
//?第三步:类外定义友元成员函数
void B::and_test(Test?&t)
{
????cout?<<?t.a?<< "?" << &t.a?<<?endl;
}
int main()
{
????Test?t1(1);
????t1.show();
????B?b;
????b.and_test(t1);
    return 0;
}

2、std::string?字符串类(掌握)

字符串对象是一种特殊类型的容器,专门设计用于操作字符串。

常用语法

 1string?s; //?创建一个字符串
 2、cout?<<?s.empty() <<?endl; //?判断是否为空
 3string?s1?= "hello";//?隐式调用构造函数
 4string s2("world"); //?显示调用构造函数
 5//?==?!=?<?>?判断的编码
????cout?<< (s1?==?s2) <<?endl; //?0?不相等
????cout?<< (s1?!=?s2) <<?endl; //?1
????cout?<< (s1?<?s2) <<?endl;  //?1
????cout?<< (s1?>?s2) <<?endl;  //?0
 6string s3(s2);//?拷贝构造
 7//?参数1:char*?原字符串
    //?参数2:保留的字符数
    string s4("ABCDEFG",3);//ABC?字符截取:保留的字符数
 8//?参数1:std::string?原字符串
    //?参数2:不保留的字符数,从头开始
    string s5(s2,3);    //?ld?字符截取:不保留的字符数,剩下的字符数
 9//?参数1:字符数量
    //?参数2:字符内容?char
    string s6(5,'a');//?aaaaa??打印字符内容
10swap(s5,s6); //?ld?aaaaa->aaaaa?ld?交换两个字符串内容
11string?s7?=?s5?+?s6;//aaaaald?字符串拼接
12、s7.append("jiajia");//?aaaaaldjiajia?向后追加字符串
13、s7.push_back('s');//?aaaaaldjiajias?向后追加单字符
14//?参数1:插入的位置
    //?参数2:插入的内容
????s7.insert(1,"234");//a234aaaaldjiajias??插入
15//?参数1:起始位置
    //?参数2:删除字符串的数量
????s7.erase(2,5);//?a2aldjiajias?删除字符串
16//?参数1:起始位置
    //?参数2:被替换的字符数
    //?参数3:替换的新内容
????s7.replace(0,3,"*****"); //?*****ldjiajias?指定替换
17、s7.clear();//0?清空
    string?s8?= "hahaha";//?直接赋值初始化(隐式调用构造函数)
18//?参数1:拷贝的目标
    //?参数2:拷贝的字符串数量
    //?参数3:拷贝的起始位置
????s8?= "ABCDEFGH";
????char?arr[20] = {0};
????s8.copy(arr,6,1);//从某个位置开始拷贝几个字符,需要初始化?否则有乱码
????cout?<<?arr?<<endl; //?BCDEFG
19//?C++?string?到?c?string?用到了c语言的strcpy
    //?c_str?C++的字符串转成C语言的字符数组
    //?c_str?返回一个?const?char?*
????char?c[20] = {0};
    strcpy(c,s8.c_str());
????cout?<<?c?<<?endl;  //?ABCDEFGH

#include?<iostream>
#include?<string.h>
using namespace?std;
int main()
{
????string?s; //?创建一个字符串
    //?判断是否为空
????cout?<<?s.empty() <<?endl;
    //?隐式调用构造函数
????string?s1?= "hello";
????cout?<<?s1?<<?endl;
    //?显示调用构造函数
????string?s2("world");
????cout?<<?s2?<<?endl;
    //?==?!=?<?>?判断的编码
????cout?<< (s1?==?s2) <<?endl; //?0?不相等
????cout?<< (s1?!=?s2) <<?endl; //?1
????cout?<< (s1?<?s2) <<?endl;  //?1
????cout?<< (s1?>?s2) <<?endl;  //?0
    //?拷贝构造
????string?s3(s2);
????cout?<<?s3?<<?endl;
    //?参数1:char*?原字符串
    //?参数2:保留的字符数
????string?s4("ABCDEFG",3);//字符截取:保留的字符数
????cout?<<?s4?<<?endl; //?ABC
    //?参数1:std::string?原字符串
    //?参数2:不保留的字符数,从头开始
????string?s5(s2,3);    //字符截取:不保留的字符数,剩下的字符数
????cout?<<?s5?<<?endl;//?ld?
    //?参数1:字符数量
    //?参数2:字符内容?char
????string?s6(5,'a');//打印字符内容
????cout?<<?s6?<<?endl;//aaaaa?
    //?交换
????cout?<< "原字符串s5?=?" <<?s5?<<"?"<< "原s6=" <<?s6?<<?endl;
    swap(s5,s6); //?aaaaa?ld?交换两个字符串内容
????cout?<< "后s5=?" <<?s5?<<"?"<< "后s6=" <<?s6?<<?endl;
    //?字符串连接
????string?s7?=?s5?+?s6;//字符串拼接
????cout?<<?s7?<<?endl; //?aaaaald
    //?向后追加字符串
????s7.append("jiajia");
????cout?<<?s7?<<?endl; //?aaaaaldjiajia
    //?向后追加单字符
????s7.push_back('s');
????cout?<<?s7?<<?endl; //?aaaaaldjiajias
    //?插入
    //?参数1:插入的位置
    //?参数2:插入的内容
????s7.insert(1,"234");
????cout?<<?s7?<<?endl; //?a234aaaaldjiajias
    //?删除字符串
    //?参数1:起始位置
    //?参数2:删除字符串的数量
????s7.erase(2,5);
????cout?<<?s7?<<?endl; //??a2aldjiajias
    //?替换
    //?参数1:起始位置
    //?参数2:被替换的字符数
    //?参数3:替换的新内容
????s7.replace(0,3,"*****"); //?*****ldjiajias
????cout?<<?s7?<<?endl;
    //?清空
????s7.clear();
????cout?<<?s7.size() <<?endl;  //?0
    //?直接赋值初始化(隐式调用构造函数)
????string?s8?= "hahaha";
????cout?<<?s8?<<?endl;
????s8?= "ABCDEFGH";
????cout?<<?s8?<<?endl;
    //?参数1:拷贝的目标
    //?参数2:拷贝的字符串数量
    //?参数3:拷贝的起始位置
    char?arr[20] = {0};
????s8.copy(arr,6,1);
????cout?<<?arr?<<endl; //?BCDEFG
    //?C++?string?到?c?string?用到了c语言的strcpy
    //?c_str?C++的字符串转成C语言的字符数组
    //?c_str?返回一个?const?char?*
    char?c[20] = {0};
    strcpy(c,s8.c_str());
????cout?<<?c?<<?endl;  //?ABCDEFGH
    return 0;
}


文章来源:https://blog.csdn.net/m0_74937538/article/details/135332529
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。