如何在C++中启用从常量到常量的隐式类型转换

How to enable implicit type conversion from non-const to const in C++?

本文关键字:常量 类型转换 C++ 启用      更新时间:2023-10-16

以下是代码的本质:

class DM
{
public:
    int something;
    DM() : something(0) { }
};
typedef DM * dm_t;
typedef dm_t & dm_ref_t;
typedef const DM * dm_const_t;
typedef dm_const_t & dm_cref_t;
int getSomething( dm_cref_t dm ) // CALLING getSomething DOES NOT COMPILE
{
    return dm->something;
}
int getSomethingAgain( dm_const_t dm )
{
    return dm->something;
}
int getSomethingOnceMore( dm_ref_t dm )
{
    return dm->something;
}
int main()
{
    dm_t dm = new DM;
    getSomething( dm ); // COMPILER ERROR COMES FROM HERE
    getSomethingAgain( dm );
    getSomethingOnceMore( dm );
    return 0;
}

这是编译器错误:

implicit_cast.cpp: In function ‘int main()’:
implicit_cast.cpp:31: error: invalid initialization of reference of type ‘const DM*&’ from expression of type ‘DM*’
implicit_cast.cpp:13: error: in passing argument 1 of ‘int getSomething(const DM*&)’

也就是说,我有一个非常量指针,我想把它传递给一个通过引用接受常量指针的函数。如果函数通过引用接受一个非常量指针或通过值接受一个常量指针,但通过引用的常量指针不接受非常量指针,那么一切都很好。

出于安全考虑,我希望函数采用常量指针;出于一些进一步发展的原因,我希望它能通过参考。自动从非常数转换为常量应该是完全安全的。为什么g++不表演演员阵容?

我想进一步讨论一个定义为getSomething的函数。如何在每次调用时不添加显式强制转换的情况下使这些调用合法化?

它没有这样做,因为在扩展typedefs之后,您有了

int getSomething( DM const* & dm )
{
  return dm->something;
}
...
int main()
{
  DM* dm = new DM;
  getSomething( dm );
}

g++正确地不允许自动执行此操作,因为您要求对常量指针进行非常量左值引用。您当前有一个非常量指针。它不能创建临时值,因为临时值不能绑定到非常量左值引用。

现在,如果您通过常量引用获取指针,它会起作用,因为它可以绑定到临时指针。但是,我只是直接传递指针,因为通过常量引用传递指针没有任何值。

不允许这样做的原因是,如果允许的话,也会这样做(违背const系统的目的)

const int i = 5;
void foo( const int* & p)
{
   p = &i;
}
void bar()
{
   int * p; 
   foo(p); // Normally not legal
   *p = 6; // And this is why
}

话虽如此,每当我看到指针的引用时,我向开发人员提出的第一个问题就是他们为什么需要这样做。偶尔,这是因为您需要一个输出参数,但我不希望它被广泛使用。

查看C++11标准中的[conv.qual](4.4/4):

转换可以在第一个级别以外的级别添加cv限定符多级指针,受以下规则约束:。。。[注意:如果程序可以将T**类型的指针分配给const类型的指针T**(也就是说,如果允许下面的第1行),程序可以无意中修改了const对象(就像在第2行所做的那样)。

给出的例子是:

int main() {
    const char c = ’c’;
    char* pc;
    const char** pcc = &pc; // #1: not allowed
    *pcc = &c;
    *pc = ’C’; // #2: modifies a const object
}

这是针对指向指针的指针进行解释的,但出于完全相同的原因,对指针的引用也是如此。

这更像C++名称"resolution"。在您的情况下,您有一个指向const DM的指针,但您想要一个常量指针,因此必须使用typedef dm_const_t const & dm_cref_t(对常量指针的常量引用)

提供更多细节:

当您声明const int * a时,就是说a是一个指向整数的常量指针。与int const * a相同。

如果要引用类型,则声明int & b,这意味着b是对整数的引用。同理,const int & cint const & c相同(const总是限定变量,而不是类型)。

因此,如果您想要对常量指针的常量引用,则使用第二种表示法更清晰(如果不使用typedefs,也是唯一可能的表示法):int const * const & d,这意味着d是对整数常量指针的常数引用。使用typedefs:

typedef const int * int_cptr;
typedef const int_cptr & int_cptrcref;

证明:http://ideone.com/V48Kxe

您不能。

您传递的是指针,这可能意味着在函数执行后,可能会有两个对同一内存的不同引用,一个声明为常量,一个则声明为非常量。

如果使用非常量引用来更改内存,那么常量引用的底层内存会突然发生更改,这将是不正确的行为。