第24课 经典问题解析二

1. 关于析构的疑问

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

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

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

  ③调用类自身的构造函数

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

 

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

 

【实例分析】构造析构顺序  24-1.cpp

#include <stdio.h>

 

class Member

{

private:

    const char* ms;

 

public:

    Member(const char* s)

    {

        printf("Member(const char* s): %s\n", s);

        ms = s;

    }

 

    ~Member()

    {

        printf("~Member(): %s\n", ms);

    }

};

 

class Test

{

private:

    Member mA;//成员函数是按声明顺序构造的

    Member mB;

 

public:

    Test():mB("mB"), mA("mA")

    {

        printf("Test()\n");

    }

 

    ~Test()

    {

        printf("~Test()\n");

    }

 

};

 

Member gA("gA");

 

int main()

{

    Test t;

 

    return 0;

}

//输出结果(先构造全局对象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对象疑问

(1)const关键字能够修饰对象,使之能为只读对象,即成员变量不允许被改变

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

 

3. const成员函数

(1)const成员函数不能直接改写成员变量的值

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

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

(4const成员函数的定义:

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

 

【编程实验】类的const函数初探  24-2.cpp

#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)从程序运行的角度看对象数据函数构成,其中数据位于栈、堆或全局数据区中,而函数只能位于代码段

(3)结论:

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

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

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

  ④方法隐藏参数this指针用于指代当前对象

 

【编程实验】成员函数的秘密  24-3.cpp

#include <stdio.h>

 

class Test

{

private:

    int mi;

 

public:

    int mj;

    Test(int i);

    Test(const Test& t);

    int getMI();

 

    void print();

};

 

Test::Test(int i)

{

   mi = i;

   printf("Test(int i)\n");

 

}

 

Test::Test(const Test& t)

{

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

    mi = t.mi;       //这里t.mi为private属性,但编译仍然能通过。是因为编译器开了个后门,

                      //允许类的成员函数直接访问由该类创建的任何对象的局部变量。

    printf("Test(const Test& t)\n");

}

 

int Test::getMI()

{

    return mi;

}

 

void Test::print()

{

    printf("&mi = %p\n", &mi);

    printf("this = %p\n", this);

}

 

int main()

{  

    //以下演示3种初始化方法

    Test t1(1);

    Test t2 = 2;

    Test t3 = Test(3);//手动调用构造函数,由Test(3)产生的临时对象会被编译器优化掉

                      //Test(int i);

 

    printf("\n");

 

    //t1、t2、t3的内存地址各不相同。各自的mi地址也不同。但print函数地址是一样的

 

    printf("t1.getMI() = %d\n", t1.getMI());  //1

    t1.print();

    printf("&t1 = %p\n", &t1);              

    printf("&t1.print() = %p\n", &t1.print);

 

    printf("\n");

 

    printf("t2.getMI() = %d\n", t2.getMI());  //2

    t2.print();

    printf("&t2 = %p\n", &t2);

    printf("&t2.print() = %p\n", &t2.print);

 

    printf("\n");

 

    printf("t3.getMI() = %d\n", t3.getMI());  //3

    t3.print();

    printf("&t3 = %p\n", &t3);

    printf("&t3.print() = %p\n", &t3.print);

 

 

    return 0;

}

 

 

5. 小结

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

(2)const关键字能够修饰对象,得到只读对象

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

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

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

posted @ 2018-12-09 17:14  梦心之魂  阅读(147)  评论(0编辑  收藏  举报