C++梁哥笔记day10 | 我的日常分享

C++梁哥笔记day10

类与对象

一、const修饰成员函数

用const修饰的成员函数,const修饰this指针指向的内存区域,成员函数体内不可以修改本类中的任何普通成员变量,当成员变量类型符用mutable修饰时例外。

1
2
3
4
//const 修饰的是成员函数
void myFun() const{
//函数体内部不能修改普通成员变量 mutable修饰时除外
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Data{
private:
int data;
mutable int num;
public:
Data(){
cout<<"无参构造"<<endl;
}
Data(int data){
this->data = data;
cout<<"有参构造"<<endl;
}
Data(Data const &ob){
cout<<"拷贝构造"<<endl;
}
~Data(){
cout<<"析构函数"<<endl;
}
void myfun() const
{
//data = 200;//error: assignment of member 'Data::data' in read-only object
num = 1000;//声明前面加了mutable 可以修改(打破规则)
}
};

运行结果:
图片


二、const修饰对象(常对象)

常对象只能调用const的成员函数,常对象可访问const或非const数据成员,不能修改,除非成员用mutable修饰
一般const修饰对象与const修饰成员函数配合使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
class Data{
private:
int data;
mutable int num;
public:
int data1;
mutable int num1;
public:
Data(){
cout<<"无参构造"<<endl;
data1 = 10;
num1 = 20;
}
Data(int data){
this->data = data;
cout<<"有参构造"<<endl;
}
Data(Data const &ob){
cout<<"拷贝构造"<<endl;
}
~Data(){
cout<<"析构函数"<<endl;
}
void myfun() const
{
//data = 200;//error: assignment of member 'Data::data' in read-only object
num = 1000;//声明前面加了mutable 可以修改(打破规则)
}
void myfun1(){

}
void myfun2() const{

}

};

void test01(){
const Data ob1;
cout<<ob1.data1<<endl;
cout<<ob1.num1<<endl;
//ob1.data1 = 100;//error: assignment of member 'Data::data' in read-only object
ob1.num1 = 200;//加了mutable 可以 修改

cout<<ob1.data1<<endl;
cout<<ob1.num1<<endl;


cout<<"-------------------"<<endl;
//myfun1()即使里面没有修改成员变量的值也会报错 因为编译器不知道到底用户有没有修改 它不是智能的 所以编译器会认为你修改了 所以不能调用
//如果要调用成员函数必须加const修饰 比如myfun2()
//ob1.myfun1();//error: passing 'const Data' as 'this' argument discards qualifiers [-fpermissive] ^

//myfun2()不能修改成员变量 除非加了mutable修饰的成员变量
ob1.myfun2();
}

运行结果:
图片


三、友元

类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部访问,但是有时候需要在类的外部访问类的私有成员而不借助公有的函数,怎么办呢?解决办法是使用友元函数,友元函数是一种特权函数,C++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:比如你的家,有客厅,有你的卧室,那么你的客厅是public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。

友元语法:
friend关键字只出现在声明处,其他类、类成员函数、全局函数都可声明为友元,友元函数不是类的成员,不带this指针,友元函数可访问对象任意成员属性,包括私有属性。

  • 普通全局函数作为友元

将全局函数在类中加friend关键字声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class Room{
//在类中加friend关键字声明,放在类中任何位置都可,private、public中都行
friend void goodFoundationFriends(Room &ob);
private:
string livingRoom;
string bedRoom;
public:
Room(){
livingRoom = "客厅";
bedRoom = "卧室";
}
};
void goodFoundationFriends(Room &ob){
//这里为什么要传入类的对象呢? 因为一个全局函数不一定是一个类的友元,需要传入类的对象确定访问的是哪一个类。
cout<<"好基友访问了"<<ob.livingRoom<<endl;
cout<<"好基友访问了"<<ob.bedRoom<<endl;
}

int main(int argc, char *argv[])
{
Room ob1;
goodFoundationFriends(ob1);
return 0;
}

运行结果:
图片

  • 类的成员函数作为另一个类的友元

    1. 问题一:为什么会报错?
      图片
      类Room的定义在GoodFriend类后面,当编译到GoodFriend中有Room的时候,Room还没有定义。但是不能将Room的定义提前在GoodFriend类前,这样还是会出现问题,报错GoodFriends和其中的visit未定义。可以在GoodFriend前对Room进行声明.class Room;
    2. 问题二
      图片
      将Room类声明后没有报错了,但是出现了类中成员未定义的错误,如果我们将成员也去声明那就没有意义,那怎么做呢?
      我们将GoodFriend中的visit1函数在类中声明,在类外定义,定义的时候在Room类之后就行了。
    3. 问题三
      图片
      这个报错怎么解决呢?为什么还是没有权限操作私有的成员。在类中对visit1方法的声明要表明其属于类,不然就跟普通全局函数一样了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <iostream>

using namespace std;
class Room;
class GoodFriends{
public:
// void visit1(Room &ob){
// cout<<"好朋友访问了你的"<<ob.livingRoom<<endl;
// cout<<"好朋友访问了你的"<<ob.bedRoom<<endl;
// }
void visit1(Room &ob);
};

class Room{
friend void GoodFriends::visit1(Room &ob);
private:
string livingRoom;
string bedRoom;
public:
Room(){
livingRoom = "客厅";
bedRoom = "卧室";
}
};
void GoodFriends::visit1(Room &ob){
cout<<"好朋友访问了你的"<<ob.livingRoom<<endl;
cout<<"好朋友访问了你的"<<ob.bedRoom<<endl;
}
int main(int argc, char *argv[])
{
Room ob1;
GoodFriends ob2;
ob2.visit1(ob1);
return 0;
}

运行结果:
图片

  • 一个类的整体作为另一个类的友元

即一个类的所有函数都可以访问另一个类的私有数据

这个时候可以在上面类的成员函数作为另一个类的友元的基础上,将友元声明部分修改成类的友元就行,或者将两个类调换顺序,将Room类放在GoodFriends类的前面。对GoodFriends类在Room之前进行一下声明就行,但是好像不声明也不会报错。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <iostream>

using namespace std;
class GoodFriends;
class Room{
friend class GoodFriends;
private:
string livingRoom;
string bedRoom;
public:
Room(){
livingRoom = "客厅";
bedRoom = "卧室";
}
};

class GoodFriends{
public:
void visit1(Room &ob){
cout<<"好朋友访问了你的"<<ob.livingRoom<<endl;
cout<<"好朋友访问了你的"<<ob.bedRoom<<endl;
}
};
int main(int argc, char *argv[])
{
Room ob1;
GoodFriends ob2;
ob2.visit1(ob1);
return 0;
}

图片