返回值为引用或指针的成员函数加const要注意

在C++中,对于不修改数据成员的成员函数,通常会加上const修饰。但当const成员函数返回引用或指针时,可能会导致意外的修改。文章通过代码示例讨论了这种情况,并提出了个人建议,即可以通过在返回值上加const或者限制返回值的访问级别来避免数据成员被意外修改。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

成员函数与const

        对于不改变类内部成员的成员函数,我们都要在函数后面加上const,对于会改变数据成员的函数则不加const。对成员函数加上const有明确的限制行为:调用该成员函数不会改变内部数据成员。但是,如果const函数的返回值是引用或指针呢?这种情况到底要不要对返回值加上const呢?先来看一段示例:

代码示例与结果

#include <iostream>
using namespace std;

struct Node {
    Node* next;
    int value;

    Node() : next(0), value(0){

    }
};


class TestList {
    typedef Node* node_ptr;
    typedef const Node* const_node_ptr;
private:
    node_ptr header;

public:
    TestList() : header(0){

    }

    TestList(node_ptr n) : header(n){

    }

    void print() const {
        node_ptr tmp = header;
        while (tmp != 0){
            cout << tmp->value << (tmp->next == 0 ? "" : ", next: ");
            tmp = tmp->next;
        }
        cout << endl;
    }

    void setHeader(node_ptr n) {
        header = n;
    }

    node_ptr getHeaderPtr() const {
        return header;
    }

    node_ptr& getHeaderRef() const {
        return (node_ptr&)header;
    }
};

int main(int argc, char** argv){
    Node header;
    header.value = 1;

    TestList tl(&header);
//    tl.setHeader(&header);
    cout << "tl ori: " << endl;
    tl.print();

    Node* nptr = tl.getHeaderPtr();
    nptr->value = 2;
    cout << "tl node value can modify by pointer: " << endl;
    tl.print();

    Node refNode;
    refNode.value = 3;
    refNode.next = &header;
    tl.getHeaderRef() = &refNode;
    cout << "tl node can modify by reference: " << endl;
    tl.print();

    cout << "---------------------- const object ----------" << endl;
    const TestList ctl(&header);
    //tl.setHeader(&header);
    cout << "ctl ori: " << endl;
    ctl.print();

    nptr = ctl.getHeaderPtr();
    nptr->value = 5;
    cout << "ctl node value can modify by pointer: " << endl;
    ctl.print();

    Node crefNode;
    crefNode.value = 6;
    crefNode.next = &header;
    ctl.getHeaderRef() = &crefNode;
    cout << "ctl node can modify by reference: " << endl;
    ctl.print();
}
上面示例代码的输出结果:

tl ori: 
1
tl node value can modify by pointer: 
2
tl node can modify by reference: 
3, next: 2
---------------------- const object ----------
ctl ori: 
2
ctl node value can modify by pointer: 
5
ctl node can modify by reference: 
6, next: 5
        由以上输出可以看到,通过修改const成员函数返回的引用或指针可以修改对象内部的值。这与const函数只能读取内部数据成员(加mutable的数据成员不包括在内)是否相矛盾呢?const函数本身是不会修改数据成员的,但是通过它的返回值可以在外部修改对象内部数据。如果对象是non-const的,这种情况还可以接受;但是如果对象是const的,这种情况就不是所期望的了。

个人建议

        要防止这种情况发生可以对返回值加const,或者对于在类内部需要把返回值作为左值的则把访问级别限制为public以下(需要再外部修改数据成员的,则提供修改器)。如:

    const_node_ptr getHeaderPtr() const {
        return header;
    }

    const node_ptr& getHeaderRef() const {
        return (node_ptr&)header;
    }

protected:
    node_ptr getHeaderPtr() const {
        return header;
    }

    node_ptr& getHeaderRef() const {
        return (node_ptr&)header;
    }

        当然,对于在成员函数内部通过指针修改数据的就只能自己注意了。


### C++ 中 `const` 关键字在成员函数中的应用 在C++中,`const` 关键字用于修饰类的成员函数,表明该成员函数不会修改对象的状态。这不仅有助于提高代码的安全性和可读性,还允许常量对象调用这些标记为 `const` 的成员函数。 当声明成员函数时,在参数列表之后上 `const` 可以指示此方法承诺不对本对象的数据成员进行更改: ```cpp class Example { public: int getValue() const; // 声明为const成员函数 private: int value; }; ``` 上述例子展示了如何将获取值的方法设置成不可变的操作[^1]。通过这种方式,编译器能够确保此类函数内部确实没有改变实例变量的行为,并且可以在更广泛的情况下安全地使用它们——比如针对只读的对象表达式。 对于含有指针类型的返回值是形参的情况,如果希望强调所涉及的内容也不应被改动,则同样可以附 `const` 来进一步限定其行为: ```cpp class StringContainer { public: const char* getData() const; // 返回指向字符数组(字符串)的常量指针 // 同时保证自身状态不变 void setData(const char* newData); // 接收一个指向常量数据的指针作为输入, // 表示传入的数据不应在此处发生变更 private: char data[100]; }; ``` 值得注意的是,虽然这里讨论的主题并非直接关于 `NULL` 者 `(void*)0` 这样的特殊指针值,但在实际编码过程中遇到涉及到指针操作的地方,理解并正确运用 `const` 对于维护健壮的应用程序至关重要[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值