const指针引出来的一个考题

引子

        关于const指针、const引用、以及const形参和const实参的内容,《C++primer》书中有介绍,并且有举例还有习题,但都是以简单类型举例,const对象的指针、const对象的引用、const对象的形参,const对象的实参的例子基本没有。虽然说可以举一反三,但对大部分人来说还是很难理解。下面从一个考题中抽出一段代码,通过分析促进大家理解相关内容。

迷雾重重:

        分析下面代码,查找代码错误原因。

struct CDog
{
    int m_age;
    CDog(int ia):m_age(ia){}
    void ShowAge(){
        cout << m_age << "," << endl; 
    }
};
void UseObj(const CDog* pData)
{    
    pData->m_age = 20; //位置1、编译错误
    pData->ShowAge();  //位置2、编译错误
}
int main()
{
    CDog* oData = new CDog(9);
    UseObj(oData);
    cout << oData->m_age;
    delete oData;
    return 0;
}

        上面代码有2处错误

        1)pData->m_age = 20;的错误

                这处错误的原因好理解,常对象指针(指向的常量对象的指针)指向值是不能修改的。

        2)  pData->ShowAge();  这里编译也出错?什么原因呢? 

抽丝剥茧:

        难道是void UseObj(const CDog* pData)函数中const的原因,尝试修改main函数如下:

int main()
{
//    CDog* oData = new CDog(9); 修改为:
    const CDog* oData = new CDog(9);
    ...
}

        编译仍然报错,为什么呢?还是看看VS2017下的错误提示吧:

error C2662: “void CDog::ShowAge(void)”: 不能将“this”指针从“const CDog”转换为“CDog &”

        先复习一下this指针的概念(百度百科):this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this指针的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。

        仔细理解上面这句话,结合我们的例子,可以把我们的成员函数改写一下,这样就好理解了。

成员函数表面上的形式成员函数实际的形式
void CDog::ShowAge()void ShowAge(CDog *this)

        这样就可以理解上面代码的编译错误提示了。

凶手浮现:

上面代码编译错误原因:成员函数ShowAge中定义的this指针类型是CDog,同时由于函数

void UseObj(const CDog* pData)定义的形参带const的原因,将实参从CDog指针类型转为了const CDog指针类型,那么它对应的对象的this指针类型也变成了const CDog类型。这样对于成员函数ShowAge(CDog *this)而言,需要将const CDog转为CDog,转换失败,导致错误。

解决办法

1、将void UseObj(const CDog* pData)改为void UseObj(CDog* pData),这并不是这个考题真正要考察的内容。

2、将CDog类中 void ShowAge()的定义改为void ShowAge() const{  ...   },这才是出题者真正想要的答案。如下面代码:

//  void ShowAge() {  修改为
    void ShowAge() const {
        cout << m_age << "," << endl; 
    }

这里的const也是C++面试经常问道的,我们都知道常成员函数内部不能修改此类的成员变量的值,至于为什么,很多人不清楚,但当看到如下形式的常成员函数时:void ShowAge(const CDog *this),我们就可以理解为什么了,这才是常成员函数中const真正的位置。

风云再起:

同样是上面的代码,我们将裸指针改为智能指针。

struct CDog
{
    int m_age;
    CDog(int ia):m_age(ia){}
    void ShowAge() {
        cout << m_age << "," << endl; 
    }
};
void UseObj(const shared_ptr<CDog> pData)
{    
   pData->ShowAge();  //编译不报错,为什么???
}
int main()
{   
	shared_ptr<CDog> oData(new CDog(9));
    UseObj(oData);
	cout << oData->m_age;
    return 0;
}

我们编译、运行此代码。发现这个例子中pData->ShowAge()这句并不报错,程序运行正常,为什么?

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值