0

请考虑以下代码。

struct foo
{
};

template<typename T>
class test
{
public:   

    test() {} 

    const T& value() const
    {
        return f;
    }

private:
    T f;
};


int main()
{
    const test<foo*> t;
    foo* f = t.value();
    return 0;
}

t是一个const变量,value()是一个返回的常量成员函数const T&。AFAIK,一个const类型不能分配给一个非常量类型。但是如何foo* f = t.value();编译得很好。这是如何发生的,我如何确保value()只能分配给const foo*

编辑

我发现,这是在使用模板时发生的。以下代码按预期工作。

class test
{
public:   

    test() {} 

    const foo* value() const { return f; }

private:
    foo* f;
};


int main()
{
    const test t;
    foo* f = t.value(); // error here
    return 0;
}

为什么使用模板时会出现问题?

4

3 回答 3

6

因为您有两个间接级别 - 在您的 main 函数中,该调用value返回对指向非 const 的 const 指针的引用foo

这可以安全地复制到指向非 const 的非 const 指针中foo

如果您使用 实例化testconst foo *那将是另一回事。

const test<const foo*> t;
foo* f = t.value(); // error
const foo* f = t.value(); // fine
return 0;

更新

来自评论:

value() 返回 const T& 只能分配给另一个 const 类型。但在这种情况下,编译器安全地允许转换。

const 数据只能被读取。它不能被写入(“变异”)。但是复制一些数据是一种读取方式,所以没关系。例如:

const int c = 5;
int n = c;

在这里,我有一些 const 数据c,我将数据复制到一个非常量变量 n 中。没关系,它只是读取数据。中的值c尚未修改。

现在,假设您foo有一些数据:

struct foo { int n; };

如果我有一个指向其中之一的非常量指针,我可以n通过指针修改值。您要求test模板存储指向非 const 的指针foo,然后创建test. 因此,只有指针地址是恒定的。没有人可以改变存储在指针里面的地址test,所以不能让它指向另一个对象。但是,它指向的对象可以修改其内容。

更新 2:

当您制作示例的非模板版本时,您犯了一个错误。为了使它正确,您需要替换foo *每个有T.

const T& value() const

请注意,您在那里有一个对 const 的引用T。所以返回值将是对 const: a 的引用foo *。只有指针地址不能修改。它指向的对象可以修改其内容。

在您的第二个示例中,您摆脱了引用部分,这改变了含义并使const修饰符应用于指针指向的对象,而不是应用于指针本身。

于 2010-02-20T18:37:02.797 回答
1

使用以下模板特化:

template<typename T>
class test<T*>
{
public:

    test() {}

    const T* value() const
    {
        return f;
    }

private:
    T* f;
};

包括这个之后,g++ 说:

d.cpp: In function ‘int main()’:
d.cpp:41: error: invalid conversion from ‘const foo*’ to ‘foo*’
于 2010-02-20T18:39:30.623 回答
1

您的代码没有任何问题,对指针的 const 引用仅意味着您不能修改指针,但指向的对象仍然是完全可变的。如果在您的函数内部您尝试更改成员main指向的地址,您会发现您不能:封装被完美保留。ft

这与使以下代码有效的原理相同:

void foo(std::vector<int *> const & v)
{
    *v[0] = 0; // op. [] returns const & to int *
}

刚接触 C++ 的人通常会对这种行为感到惊讶,因为对他们来说 const 向量不应该允许修改其元素。事实上它不会,因为存储在向量中的指针不会改变(它一直指向同一个地址)。它是被修改的指向对象,但向量并不关心这一点。

唯一的解决方案是按照 Amit 所说的去做,并为您的班级提供专业化的T*.

于 2010-02-20T19:38:45.620 回答