C++面向对象程序设计(三)——3.类和对象提高

网友投稿 795 2022-05-30

C++面向对象程序设计(三)——3.类和对象提高

本文是中国大学MOOC,北京大学程序设计与算法(三)C++面向对象程序设计第三周笔记。本课程学习的github仓库欢迎Fork

本文目录

C++面向对象程序设计(三)——3.类和对象提高

一 this 指针

C++ 到 C程序的翻译

二 静态成员

基本概念

如何访问静态成员

1.类型::成员名

2.对象名.成员名

3.指针->成员名

4.引用.成员名

三 成员对象和封闭类

基本概念

封闭类构造函数和析构函数的执行顺序

四 友元

友元函数

友元类

五 常量成员函数

六 mutable成员变量

一 this 指针

C++ 到 C程序的翻译

//C++ class CCar{ public: int price; void SetPtice(int p); }; void CCar::SetPrice( int p ){ price = p; } int main(){ CCar car; car.SetPrice( 20000 ); return 0; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

//C struct CCar{ int price; }; void SetPrice( struct CCar * this, int p) { this -> price = p; } int main(){ struct CCar car; SetPrice( & car, 20000 ); return 0; }

1

2

3

4

5

6

7

8

9

10

11

12

13

对比一下这两个程序,我们可以看到:

每个类的非静态成员函数中都隐含包含一个this指针,类型为当前类类型的指针类型

this 作用就是指向成员函数所作用的对象。在非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针。

我们可以看一个案例:

class Complex{ public: double real,imag; void Print(){ cout << real << "," << imag; } Complex( double r, double i ):real( r ),imag( i ) {} Complex AddOne(){ this -> real ++; //等价于 real++ this -> Print(); //等于于 Print return * this; } }; int main(){ Complex c1(1,1),c2(0,0); c2 = c1.AddOne(); return 0; }//输出 2,1

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

需要注意的是:

静态成员函数中不能使用this指针,因为静态成员函数并不具体作用于某个对象。所以,静态成员函数的真实参数的个数,就是程序中写出的参数个数。

然而,类的非静态成员函数,真实的参数比所写的参数多1,多的这个就是this指针。

二 静态成员

基本概念

在定义前面加了static关键字的成员

class CRectangle { private: int w, h; static int nTotalArea; //静态成员变量 static int nTotalNumber; public: CRectangle(int w_, int h_); ~CRectangle(); static void PrintTotal(); //静态成员函数 };

1

2

3

4

5

6

7

8

9

10

11

静态成员变量为所有对象共享,且sizeof运算符不会计算静态成员变量

class CMyclass{ int n; static int s; }; //sizeof(CMyclass) 等于 4

1

2

3

4

5

普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享

普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。所以实际上静态成员不需要通过对象就能访问。

如何访问静态成员

CRectangle::PrintTotal();

1

CRectangle r; r.PrintTotal();

1

2

CRectangle * p = &r; p -> PrintTotal();

1

2

CRectangle & ref = r; int n = ref.nTotalNumber;

1

2

静态成员变量本质上是全局变量,哪怕一个对象都不存在,类的静态成员变量也存在

静态成员函数本质上是全局函数,主要目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去想一个整体,易于维护和理解

class CRectangle { private: int w, h; static int nTotalArea; //静态成员变量 static int nTotalNumber; public: CRectangle(int w_, int h_); ~CRectangle(); static void PrintTotal(); //静态成员函数 }; CRectangle::CRectangle(int w_,int h_ ) { w = w_; h = h_; nTotalNmuber ++; nTotalArea += w * h; } CRectangle::~CRectangle() { nTotalNumber --; nTotalArea -= w * h; } void CRectangle::PrintTotal() { cout << nTotalNumber << "," <

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

要注意的是:在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数

必须在类外面对静态函数变量进行说明或初始化

void CRectangle::PrintTotal() { cout << w << "," << nTotalNumber << "," << nTotalArea << endl; //error } CRectangle::PrintTotal(); //解释不通,w到底属于哪个对象?

1

2

3

4

5

三 成员对象和封闭类

基本概念

有成员对象的类叫封闭类

class CTyre { //轮胎类 private: int radius; //半径 int width; //宽度 public: CTyre( int r, int w ):radius(r),width(w){}//初始化列表,为成员变量指定初始值 }; class CEngine{ //引擎类 }; class CCar{ //汽车类 private: int price; //价格 CTyre yre; CEngine engine; public: CCar( int p, int tr, int tw ); }; CCar::CCar( int p, int tr, int w):price(p),tyre(tr,w) {}; int main() { CCar car( 20000, 17, 225 ); return 0; }

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

上面的例子中,如果CCar类不定义构造函数,那么下面的语句编译会出错

CCar car;

因为编译器不明白car.type,该如何初始化。car.engine的初始化没问题,用默认构造函数就可以了。

任何生成封闭类对象的语句,都要使得编译器明白,对象中的成员对象,是如何初始化的。完成这一任务的方法是通过封闭类的构造函数的初始化列表,成员对象初始化列表中的参数可以是任意复杂的表达式,可以包括函数,变量,只要表达式中的函数或变量有定义就行。

封闭类构造函数和析构函数的执行顺序

封闭类对象生成时,先所有成员对象的构造函数,然后才执行封闭类的构造函数

对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与成员初始化列表次序无关

封闭类对象消亡时,先执行封闭类析构函数,再执行成员对象的析构函数。次序和构造函数的调用次序相反

class CTyre{ public: CTyre(){cout << " Ctyre contructor "<< endl; } ~CTyre(){cout << " Ctyre destructor "<< endl; } } class CEngine{ public: CEngine(){cout << "CEngine contructor" << endl;} ~CEngine(){cout << "CEngine destructor" << endl;} } class CCar{ private: CEngine engine; CTyre tyre; public: CCar(){ cout << "CCar constructor" << endl;} ~CCar(){ cout << "CCar destructor" << endl;} } int main(){ CCar car; return 0; } //输出结果 //CEngine contructor //Ctyre contructor //CCar constructor //CCar destructor //Ctyre destructor //CEngine destructor

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

封闭类的对象如果用默认复制构造函数初始化,那么它包含的成员对象也会用复制构造函数初始化

class A{ public: A(){cout << "default" << endl;} A(A & a){ cout << "Copy" << endl;} }; class B {A a;}; int main(){ B b1, b2(b1); return 0; } //输出: //default //Copy //b2.a是用类A的复制构造函数初始化的。 //调用复制构造函数的实参是b1.a

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

四 友元

友元函数

一个类的友元函数可以访问该类的私有成员

class CCar; class CDriver{ public: void ModifyCar(CCar * pCar); }; class CCar { private: int price; friend int MostExpensiveCar( CCar cars[], int total ); //声明友元 friend void CDriver::ModifyCar( CCar * pCar ); //声明友元 } void CDriver::ModifyCar( CCar * pCar ) { pCar->price += 1000 ; //改装后变贵了 } int MostExpensiveCar( CCar cars[],int total ) //最贵汽车价格 { int tmpMax = -1; for( int i = 0; i < total ; ++ i ) { if(car[i].price > tmpMax) tmpMax = cars[i].price; } return tmpMax; } int main(){ return 0; }

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

当然我们还可以把一个类的成员函数(包括析构,构造等)说明为另一个类的友元

class B{ public: void function(); }; class A{ friend void B::function(); }

1

2

3

4

5

6

7

8

友元类

如果A是B的友元类,那么A的成员函数可以访问B的私有成员

class CCar{ private: int price; friend class CDriver; //声明CDriver为友元类 }; class CDriver{ public: CCar myCar; void ModifyCar(){ //改装汽车 myCar.price += 1000; //CDriver是CCar的友元类,所以可以访问CCar的私有成员 } }; int main(){ return 0; }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

友元类之间的关系不能传递,不能继承

五 常量成员函数

如果不希望某个对象的值被改变,那么可以在对象前加const关键字

class Sample{ private: int value; public: Sample(){} void SetValue(){} }; const Sample Obj; //常量对象 Obj.SetValue (); //错误,常量对象只能使用构造函数,析构函数,有const说明的函数

1

2

3

4

5

6

7

8

9

10

类的成员函数说明后面可以加const关键字,该成员函数成为常量成员函数

常量成员函数内部不能改变属性的值,也不能调用非常量成员函数

在定义和声明成员函数时都应该用const关键字

如果一个成员函数中没有调用非常量成员函数,也没有修改成员函数变量的值,那么最好将其写成常量成员函数

如果两个函数,名字参数表都一样,但是一个有const,一个没有,算重载

六 mutable成员变量

可以在const成员函数中修改的成员变量

class CTest{ public: bool GetData() const { m_n1++; return m_b2; } private: mutale int m_n1; bool m_b2; };

1

C++面向对象程序设计(三)——3.类和对象提高

2

3

4

5

6

7

8

9

10

11

C++ 面向对象编程

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:【云驻共创】华为云大咖带你玩转云原生基础设施之K8s
下一篇:Linux开发_动态静态库创建与Makefile规则
相关文章