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

时间:2016-05-17 15:20:05

标签: c++ pointers generics const

- 大学作业 -

我已经使用了如下所示的泛型函数:

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;

我也在const中使用operator<<这个类,一切都很好,没有与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 &'

虽然我确实google了,但发现我是否在这些函数前放了另一个const

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

错误消失了。

当然,这解决了我的问题,但我宁愿知道为什么会发生这种情况以及究竟发生了什么。如果有一种简单的方法来解释我提供的两个例子之间的区别,我们将非常感激。

2 个答案:

答案 0 :(得分:1)

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;
}

答案 1 :(得分:1)

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

现在到你的第二个Collection课程。 _elements1[index]方法内部的GetElement1类型为const int&,因为在const方法中访问_elements1之前添加了const。现在出现错误的原因是因为您无法将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]