常量方法返回非常量引用可以编译通过。

3

我有一个简单的Vector类,实现了索引操作符。 从这里和其他相关问题中得知,我不确定以下代码为什么能够编译:

int main()
{
    const Vector A(5);
    cout << "A :" << A << endl;
    A[0] = 5;
    cout << "A: " << A << endl;
}

Vector.h

#pragma once
#include <iostream> 
#include <functional>

namespace vector
{
    class Vector
    {
        friend std::ostream& operator<<(std::ostream&, const Vector&);

        int n;
        int *arr; 
    public:
        Vector(int = 0); 
        ~Vector();
        Vector(const Vector&);
        Vector& operator=(const Vector&);
    private:
        void copy(const Vector&);
    public:
        int& operator[](const int) const;   
    };
}

Vector.cpp

#include "Vector.h"
#include <algorithm>
#include <utility>
#include <functional>


namespace vector
{ 
    Vector::Vector(int n) : n(n), arr(new int[n])
    {
        std::fill(arr, arr + n, 0);
    }

    Vector::~Vector()
    {
        n = 0;
        delete[] arr;
    }

    void Vector::copy(const Vector& other)
    {
        arr = new int[n = other.n];
        std::copy(other.arr, other.arr + n, arr);
    }

    Vector::Vector(const Vector& other)
    {
        copy(other);
    }

    Vector& Vector::operator=(const Vector& other)
    {
        if (this != &other)  
        {
            this->~Vector();
            copy(other);
        }
        return *this;
    }

    int& Vector::operator[](const int index) const
    {
        return arr[index];
    }

    std::ostream& operator<<(std::ostream& stream, const Vector& vec)
    {
        for (int i = 0; i < vec.n; i++)
            stream << vec.arr[i] << " ";

        return stream;
    }

}

输出:

A: 0 0 0 0 0
A: 5 0 0 0 0

一个返回非const引用的const方法(后来用于更改之前的const对象)如何能够编译通过呢?

我们缺少Vector :: arr的定义来回答。请编辑您的问题以提供一个[MCVE]。 - YSC
3
我的水晶球告诉我,您已经遇到了指针的非const可转移性问题。这篇文章介绍了相关知识 - Quentin
2个回答

11

简而言之,这是你的责任。

const成员函数中,只有数据成员本身变为const。对于arr(应该是int*类型),它将变为int * const(即const指针),而不是int const *(即指向const的指针);也就是说,指针变为const,但指向的对象并没有变为const。因此,在技术上可以返回指向非const对象的非const引用,尽管实际上可能没有太多意义。

最好重载operator[],就像大多数STL容器一样。例如:

// const version
int const & Vector::operator[](const int index) const 
{
    return arr[index]; 
}

// non-const version
int & Vector::operator[](const int index)
{
    return arr[index]; 
}

2
你可以添加这样一句话,为了实现const正确性,通常会提供一个const和一个非const重载的operator[],分别具有const和非const返回类型。 - pschill
我总是这样做,这只是为了练习目的。只想看看非const版本的方法会发生什么。 - 0lt
1
成员变量为可变的情况下没有任何问题;此时返回一个非常量引用是很有意义的(例如互斥锁集合)。 - UKMonkey

0

const 在方法声明中只是表示该方法对实例本身具有只读访问权限(就像接收 const MyType *this 而不是 MyType *this 一样)。如果 arr 是您类中指向 int 的指针,则在 const 方法内部使用时,它将被视为 int * const。但请注意,这与 const int * 不同!这就是为什么对其进行解引用会产生一个 int& 而不是 const &int 的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接