24-经典问题解析二

注:博客中内容主要来自《狄泰软件学院》,博客仅当私人笔记使用。

测试环境:Ubuntu 10.10

GCC版本:9.2.0

 

一、关于析构的疑问

        当程序中存在多个对象的时候,如何确定这些对象的析构顺序

 

1)单个对象创建时构造函数的调用顺序——1、2、3

    1、调用父类的构造过程(后续课程中讲解

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

    3、调用类自身的构造函数

                先父母——在客人——后自己

 

       析构函数与对应构造函数调用顺序相反

 

2)多个对象析构时

    -    析构顺序构造顺序相反

    构造顺序:A-B-C

    析构顺序:C-B-A

实例分析
构造与析构顺序
24-1.cpp
#include <stdio.h>

class Member
{
    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
{
    Member mA;    //成员变量mA
    Member mB;    //成员变量mB
public:
    Test() : mB("mB"), mA("mA") //成员变量顺序与构造顺序相同,不要被迷惑
    {
        printf("Test()\n");
    }
    ~Test()
    {
        printf("~Test()\n");
    }
};

Member gA("gA");    //最先调用了全局对象的构造函数

int main()
{
    Test t;    // gA    第一步父类跳过
               // mA    
               // mB    

               // Test() 第三步调用t自身构造函数

               // ~Test()
               // mB
               // mA
               // gA
    return 0;
}

操作:

1) g++ 24-1.cpp -o 24-1.out编译正确,打印结果:

Member(const char* s): gA    //全局对象Member gA("gA");
Member(const char* s): mA    //局部变量t开始实例化:客人,后自己
Member(const char* s): mB
Test()
~Test()
~Member(): mB    
~Member(): mA    
~Member(): gA            //全局对象析构函数

 

二、关于析构的答案

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

       

        堆对象的析构发生在使用delete的时候,与delete的使用顺序相关!!

 

三、关于const对象的疑问

                const关键字能否修饰类的对象?如果可以,有什么特性

 

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

2)const修饰的对象为只读对象

3)只读对象的成员变量不允许被改变(变成只读)

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

5)C++中的const成员函数

       -    const对象只能调用const的成员函数

       -    const成员函数中只能调用const成员函数

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

6)const成员函数的定义:

        Type ClassName::function(Type p)const

            类中的函数声明与实际函数定义中都必须带const关键字。

编程实验
类的const函数初探
24-2.cpp
#include <stdio.h>

class Test
{
    int mi;
public:
    int mj;
    Test(int i);
    Test(const Test& t);    //拷贝构造函数
    int getMi() const;     
};

Test::Test(int i)
{
    mi = i;
}

Test::Test(const Test& t)    //拷贝构造函数
{                 
    
}
    
int Test::getMi()const  
{
    return mi;
}

int main()
{
    Test t(1);

    return 0;
}

操作:

1) 修改代码,定义一个const Test t(1);对象,测试:

int main()
{
    const Test t(1);    //增加:修改成只读对象
    
    return 0;
}

g++ 24-2.cpp -o 24-2.out编译正常,运行正常。

 

2) 继续修改代码,增加变量int mj;测试:

class Test
{
    int mi;
public:
    int mj;                //增加:变量
    Test(int i);
    Test(const Test& t);   //拷贝构造函数
    int getMi();    
};

int main()
{
    const Test t(1);
    
    t.mj = 1000;    //增加:变量
    
    return 0;
}

编译报错:

24-2.cpp: In function ‘int main()’:
24-2.cpp:32:7: error: assignment of member ‘Test::mj’ in read-only object
  t.mj = 1000;
给只读成员变量赋值

分析:const对象对以后,对象的公有成员变量,也不能再次被修改数据。

 

3) 继续修改代码,打印t.mi内容:

int main()
{
    const Test t(1);
    
    printf("t.getMi() = %d\n", t.getMi());    //1
    
    return 0;
}

编译报错:

24-2.cpp: In function ‘int main()’:
24-2.cpp:32:37: error: passing ‘const Test’ as ‘this’ argument of ‘int Test::getMi()’ discards qualifiers [-fpermissive]
  printf("t.getMi() = %d\n", t.getMi());
错误:编译到const Test有错误,争议为int Test::getMi()丢失限定词(const)。

分析:

        只读对象只能调用const成员函数。

 

解决办法:定义和声明时,给函数增加const关键字。

class Test
{
    int mi;
public:
    int mj;
    Test(int i);
    Test(const Test& t);    //拷贝构造函数
    int getMi()const;     
};

int Test::getMi()const   
{
    return mi;
}

编译正常,打印结果:

t.getMi() = 1

4) 继续修改,在int Test::getMi() const中修改变量mi数值:

int Test::getMi()const    
{
    mi = 2;
    
    return mi;
}

编译程序,报错:

24-2.cpp: In member function ‘int Test::getMi() const’:
24-2.cpp:25:5: error: assignment of member ‘Test::mi’ in read-only object
  mi = 2;
错误:在只读对象中给成员Test::mi赋值

分析:

        只读对象中给成员Test::mi赋值。

 

5) 继续修改,在拷贝构造函数调用int Test::getMi()去掉了const

class Test
{
    int mi;
public:
    int mj;
    Test(int i);
    Test(const Test& t);    //拷贝构造函数
    int getMi();     //去掉const
};

Test::Test(const Test& t)
{
    mi = t.getMi();    //增加
}

int Test::getMi()     //去掉const
{
    return mi;
}

编译报错:

24-2.cpp: In copy constructor ‘Test::Test(const Test&)’:
24-2.cpp:20:15: error: passing ‘const Test’ as ‘this’ argument of ‘int Test::getMi()’ discards qualifiers [-fpermissive]
  mi = t.getMi();
24-2.cpp: 再拷贝构造函数'Test::Test(const Test&)'里:
24-2.cpp:20:25: 错误:编译到'const Test'时,争议为'int Test::getMi()'丢失限定符。

分析:

        const对象只能调用const类型成员函数。

 

四、关于类成员的疑问

        成员函数成员变量都是隶属于具体对象的吗?

1)从面向对象的角度

        -    对象由属性(成员变量)方法(成员函数)构成

2)从程序运行的角度

        -    对象由数据函数构成

            * 数据可以位于栈,堆和全局数据区

            * 函数只能位于代码段(代码段不能被改,编译阶段就固定)

3)结论

        -    每一个对象都拥有自己独立的属性(成员变量)    数据私有,安全

        -    所有的对象共享类的方法(成员函数)

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

        -    方法中的隐藏参数this用于指代当前对象

                    this指针用于指向当前对象地址,*this为当前对象。

编程实验
成员函数的秘密
24-3.cpp
#include <stdio.h>

class Test
{
    int mi;
public:
    int mj;
    Test(int i);
    Test(const Test& t);
    int getMi();
    void print();
};

Test::Test(int i)
{
    mi = i;
}

Test::Test(const Test& t)
{
    mi = t.mi;
}
    
int Test::getMi()
{
    return mi;
}

void Test::print()
{
    printf("this = %p\n", this);    //this是关键字
}

int main()
{
    Test t1(1);
    Test t2(2);
    Test t3(3);
    
    printf("t1.getMi() = %d\n", t1.getMi());
    printf("&t1 = %p\n", &t1);
    t1.print();
    
    printf("\n");
    
    printf("t2.getMi() = %d\n", t2.getMi());
    printf("&t2 = %p\n", &t2);
    t2.print();
    
    printf("\n");
    
    printf("t3.getMi() = %d\n", t3.getMi());
    printf("&t3 = %p\n", &t3);
    t3.print();
    
    return 0;
}

操作:

1) g++ 24-3.cpp -o 24-3.out编译正确,打印结果:

t1.getMi() = 1
&t1 = 0xbf85da68
this = 0xbf85da68
    
t2.getMi() = 2
&t2 = 0xbf85da60
this = 0xbf85da60
    
t3.getMi() = 3
&t3 = 0xbf85da58
this = 0xbf85da58

分析:

        this指针指向了当前对象地址。

 

小结

1)对象的析构顺序与构造顺序相反

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

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

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

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值