24.经典问题分析

1. 关于析构的疑问

(1)单个对象创建时构造函数的调用顺序

对象的构造函数调用不止一次,比如类的成员变量是另一个类的对象

  ①调用父类构造函数(后续课程中讲解)

  ②调用成员变量构造函数(调用顺序与声明顺序相同)

  ③调用类自身的构造函数

析构函数与对应构造函数调用顺序相反:即类自身的析构成员变量父类析构

(2)多个对象析构析构函数顺序构造函数顺序相反

【实例分析】构造函数与析构函数的调用顺序

 1 #include<stdio.h>       构造函数与析构函数的调用顺序
 2 
 3 class Member
 4 {
 5     const char* ms;   //字符指针
 6 public:
 7     Member(const char* s)
 8     {
 9         printf("Member(const char* s) : %s\n",s);
10         ms = s;
11     }
12     ~Member()
13     {
14         printf("~Member() : %s\n", ms);
15     }
16 };
17 
18 class Test
19 {
20     Member mA;           //定义的成员变量是另一个类Member的对象
21     Member mB;
22 public:
23     Test() : mB("mB"), mA("mA")           
24     {
25         printf("Test() \n");
26     }
27     ~Test()
28     {
29         printf("~Test() \n");
30     }
31 };
32 
33 Member gA(" gA");   //全局对象
34 
35 int main()
36 {
37     Test t;     //局部对象
38                 //首先构造全局对象的构造函数,Member(const char* s) : gA
39                 //然后是main()函数,单个对象t构造  :  mA     mB  
40                 //最后是自身函数的调用:Test() 
41                 //析构顺序:~Test()   mB   mA   gA
42     return 0;
43 }

//输出结果(先构造全局对象gA,进入main构造t对象)

//Member(const char* s): gA

//Member(const char* s): mA

//Member(const char* s): mB

//Test();

//~Test()                      //注意析构顺序与构造顺序是相反的!

//~Member(): mB

//~Member(): mA

//~Member(): gA

(3)不同存储区对象的析构

  ①栈对象全局对象的析构类似于入栈与出栈的顺序最后构造的对象被最先析构

  ②堆对象析构:发生在使用delete的时候delete的使用顺序相关

2. 关于const对象的疑问

 const可以修饰变量,那能不能修饰对象??如果可以有什么特性??

类比思想-----类是用户自定义的类型,是struct进化而来的关键字,struct在c语言是变量能被const修饰,那么对应的类某种角度来说也是变量,是不是也能被const修饰,

(1)const关键字能够修饰对象

(2)const修饰的对象是只读对象

(3)只读对象的成员变量不允许被改变。  (对象由一系列成员变量构成,对象只读,那么成员变量不允许改变)

(4)只读对象编译阶段的概念,在运行时无效

3. const成员函数--------不能直接改写成员变量的值

(2)const对象只能调用const成员函数。如拷贝构造函数里只能调用const成员函数

(3)const成员函数只能调用const成员函数

(4const成员函数的定义:

    Type ClassName::func(Type p) const{};       //类中函数声明与实际函数定义都必须带const关键字

                           //普通成员函数之后,函数体之前,加const关键字

复制代码
#include <stdio.h>

 

class Test

{

private:

    int mi;

 

public:

    Test(int i);

    Test(const Test& t);//t是const对象(的引用),函数内只能调用const成员函数

    int getMI() const; //const成员函数

 

    void print()      //非const成员函数

    {

        printf("mi = %d\n", mi);

    }

 

    void show() const

    {

        //print(); //错误,const成员函数不能调用非const的成员函数

       printf("mi = %d\n", mi);

    }

 

};

 

Test::Test(int i)

{

   mi = i;

}

 

Test::Test(const Test& t)

{

 

}

 

int Test::getMI() const

{

    //mi = 2; //const成员函数不能改变成员变量的值!

    return mi;

}

 

 

int main()

{

    const Test t(1); //const对象

    t.getMI();       //正确,const对象只能调用const成员函数

    t.show();        //正确,const对象只能调用const成员函数

    //t.print();     //错误,const对象不能调用非const成员函数

   

    return 0;

}
复制代码

4. 关于类成员的疑问

成员函数和成员对象都的属于类的对象吗??

(1)从面向对象的角度------------------------对象属性成员变量)和方法成员函数)构成

(2)从程序运行的角度-------------------------对象数据函数构成,其中数据位于栈、堆或全局数据区中,而函数只能位于代码段

   代码段是只读的,程序运行时不改变,待程序编译成最后的可执行程序时,代码的确定不可修改,

  对象可以动态的创建,动态的删除,对于数据也是,栈堆数据动态创建删除,对于代码不可能---------所以不可能成员函数每个都有一套,只有所有的对象共享一套成员函数,因为代码的不能动态添加删除------------那么对于那么多的对象,成员函数怎么分辨是哪个对象调用???????方法中隐藏参数this指针用于指代当前对象

(3)结论:

  ①每一个对象拥有自己独立的属性(成员变量

  ②所有的对象共享类的方法成员函数

  ③方法能够直接访问对象的属性

  ④方法中隐藏参数this指针用于指代当前对象-------当前调用成员函数的对象

成员函数与普通函数区别--------有隐藏的参数-this指针,指向当前调用函数对象的地址

  1 #include <stdio.h>
  2 
  3 class Test
  4 {
  5 private:
  6     int mi;
  7 
  8 public:
  9 
 10     int mj;
 11 
 12     Test(int i);
 13 
 14     Test(const Test& t);
 15 
 16     int getMI();      //成员函数------只有一套,所有类调用
 17 
 18     void print();
 19 
 20 };
 21 
 22 
 23 Test::Test(int i)
 24 {
 25    mi = i;
 26 
 27    printf("Test(int i)\n");
 28 }
 29 
 30 
 31 
 32 Test::Test(const Test& t)
 33 {
 34     //mi = t.getMI();//错误,t是const对象,不能调用非const成员函数
 35 
 36     mi = t.mi;        //拷贝构造函数------一种特殊的成员函数------直接访问对应类对象的成员变量
 37                       //这里t.mi为private属性,但编译仍然能通过。是因为编译器开了个后门,
 38 
 39                       //允许类的成员函数直接访问由该类创建的任何对象的局部变量。
 40 
 41     printf("Test(const Test& t)\n");
 42 }
 43 
 44 
 45 int Test::getMI()
 46 {
 47     return mi;
 48 }
 49 
 50 
 51 void Test::print()
 52 {
 53     printf("&mi = %p\n", &mi);
 54 
 55     printf("this = %p\n", this);    // this指针,值为调用print()对应对象的地址-------this指向当前对象
 56 }
 57 
 58 
 59 
 60 int main()
 61 {
 62     Test t1(1);
 63 
 64     Test t2 = 2;
 65 
 66     Test t3 = Test(3);//手动调用构造函数,由Test(3)产生的临时对象会被编译器优化掉
 67 
 68                       //Test(int i);
 69 
 70 
 71 
 72     //t1、t2、t3的内存地址各不相同。各自的mi地址也不同。但print函数地址是一样的
 73 
 74     printf("t1.getMI() = %d\n", t1.getMI());  //1
 75 
 76     printf("&t1 = %p\n", &t1);           //0xbf85da68
 77 
 78     t1.print();                          //0xbf85da68
 79 
 80     printf("&t1.print() = %p\n", &t1.print);
 81 
 82 
 83 
 84 
 85 
 86 
 87     printf("t2.getMI() = %d\n", t2.getMI());  //2
 88 
 89     t2.print();                //0xbf85da68
 90 
 91     printf("&t2 = %p\n", &t2);//0xbf85da68
 92 
 93     printf("&t2.print() = %p\n", &t2.print);
 94 
 95 
 96 
 97 
 98 
 99     printf("t3.getMI() = %d\n", t3.getMI());  //3
100 
101     t3.print();     //0xbf85da68
102 
103     printf("&t3 = %p\n", &t3);      //0xbf85da68
104 
105     printf("&t3.print() = %p\n", &t3.print);
106 
107 
108     return 0;
109 
110 }

5. 小结

(1)对象析构顺序构造顺序相反

(2)const关键字能够修饰对象,得到只读对象(只读对象只能调用const成员函数)

(3)只读对象只能调用const成员函数(不能修改成员变量的成员函数)

(4)所有对象共享类的成员函数

(5)隐藏的this指针用于表示当前对象

猜你喜欢

转载自www.cnblogs.com/liuyueyue/p/13373818.html
今日推荐