返回泛型函数中对象的引用(具有指针或非指针属性)

Returning references of objects in generic functions (with pointer or non-pointer attributes)

本文关键字:指针 属性 函数 泛型 对象 引用 返回      更新时间:2023-10-16

-大学作业-

我已经使用过如下的通用函数:

template<class T1, class T2, int max>
class Collection{
    T1* _elements1[max];
    T2* _elements2[max];
    int _count;
public:
    // ctor
    bool AddElement(const T1& e1, const T2& e2)
    {
        for (int i = 0; i < _count; i++)
            if (_elements1[i] == e1 && _elements2[i] == e2)
                return false;
        _elements1[_count] = e1;
        _elements2[_count] = e2;
        _count++;
        return true;
    }
    int GetMax()const { return max;}
    T1& GetElement1(int index)const { return *_elements1[index]; }
    T2& GetElement2(int index)const { return *_elements2[index]; }
}

main():中

Collection<int, double, 6> collection;
for (int i = 0; i < 6; i++)
    collection.AddElement(i, i + 0.4);
cout << collection << endl;

我还在这个类的operator<<中使用const,一切都很好,没有与const相关的编译器抱怨。

但是,今天我尝试了这门课的稍微不同的版本,我们应该练习,因为它将以某种形式出现在考试中

template<class T1, class T2, int max>
class Collection{
    T1 _elements1[max];
    T2 _elements2[max];
    int _count;
public:
    // ctor
    int GetMax()const { return max;}
    T1& GetElement1(int index)const { return _elements1[index]; }
    T2& GetElement2(int index)const { return _elements2[index]; }
}

这里的区别在于,T1T2不是pointers的数组,而是普通对象的数组,而且在底部,当return出现时,不需要取消引用。

然而,在后一个例子中,我得到了这个错误:

error C2440: 'return' : cannot convert from 'const int' to 'int &'

尽管我确实用谷歌搜索了一下,发现我是否在这些函数前面放了另一个const

const T1& GetElement1(int index)const { return _elements1[index]; }
const T2& GetElement2(int index)const { return _elements2[index]; }

错误消失了。

诚然,这解决了我的问题,但我更愿意了解为什么会发生这种情况,以及幕后到底发生了什么。如果有一种简单的方法来解释我提供的两个例子之间的差异,我们将不胜感激。

在第一个Collection版本中,_elements1[index]的类型为int *const&。这个const是因为您在const方法中访问_elements1(在这种情况下,实际上this就是const),也意味着您不允许修改_elements1[index]。当你取消引用_elements1[index]时,你会得到int&,这是_elements1[index]指向的东西。所以你可以从GetElement1返回它,它返回T1&

现在开始你的第二节"收藏"课。这里,GetElement1方法内部的_elements1[index]的类型是const int&,就像之前添加const一样,因为您访问了const方法内部的_elements1。现在出现错误的原因是无法将const int&隐式转换为int&

如果你想了解什么类型的_elements1[index]在不同的地方,你可以使用以下技巧:

template<typename T>
struct TD;
// ...
T1& GetElement1(int index)const { 
    TD<decltype(_elements1[index])> tt;        
    return _elements1[index]; 
    }

将输出错误,里面的确切类型在decltype:之上

error: implicit instantiation of undefined template 'TD<const int &>'
                                                        ^^^^^^^^^^^ - type of _elements1[index]
T1& GetElement1(int index)const { return _elements1[index]; }

对于成员函数,编译器将把类本身(this)作为第一个参数传递给函数。由于成员函数声明后有const限定符,GetElement1的第一个参数是const Collection,而不是Collection

编辑:

#include "iostream"
#include "string"
template<class T1, class T2, int max>
class Collection{
    T1* _elements1[max];
    T2* _elements2[max];
    int _count;
public:
    Collection() {
        for (size_t i = 0; i < max; ++i) {
            _elements1[i] = new T1{};
            _elements2[i] = new T2{};
        }
    }
    int GetMax()const { return max;}
    const T1& GetElement1(int index) const {
        // _elements1[0] = new T1{}; Error, the pointer is constant
        _elements1[0]->resize(5); // Ok, the pointed object isn't constant
        return *_elements1[index];
    }
    const T2& GetElement2(int index) const { return *_elements2[index]; }
};
int main() {
    Collection<std::string, std::string, 5> c;
    const std::string& rs = c.GetElement1(1);
    return 0;
}