【问题标题】:Is const_cast<const Type*> ever useful?const_cast<const Type*> 有用吗?
【发布时间】:2011-03-16 10:54:02
【问题描述】:

最近我发现一段 C++ 代码可以有效地执行以下操作:

char* pointer = ...;
const char* constPointer = const_cast<const char*>( pointer );

显然作者认为const_cast的意思是“添加const”,但实际上const也可以隐式添加:

const char* constPointer = pointer;

在任何情况下我真的需要const_cast to 指向常量的指针(如上例中的const_cast&lt;const Type*&gt;)?

【问题讨论】:

  • 我能想到的只有一个是强制模板实例化的特定类型 - 或重载解决方案。
  • 一个有趣的问题,虽然我不明白为什么这会使构造更有用,但您可以使用const_cast 来添加或减去volatile 以及const
  • 我也想知道它与 static_cast 有何不同
  • @Omnifarious:确实,这就是为什么使用const_cast 来添加const。 C++ 中受限转换的全部意义在于,您可以使用尽可能少的转换,包括您想要的转换。我想知道编写一个implict_cast 模板是否有用,它允许您在代码中发出转换正在发生的信号,但要确保只执行隐式转换。因此,您不会意外删除 volatile(如将 const_cast 移至指针类型)或使用显式构造函数(如将 static_cast 移至类类型)。
  • @StackedCrooked:当目标是const char*时,我认为唯一的区别是const_cast可以删除volatile,而static_cast不能。但是,对于指向类类型的指针,const_cast 不会向上转换或(更重要的是)向下转换,static_cast 会。基本上,当源类型与您想象的不完全一样时,它们会以不同的方式意外地做一些您不想要的事情。

标签: c++ casting constants const-correctness


【解决方案1】:

您有 2 个重载,并且您想强制执行 const 一个。当您根据另一个来称呼一个时,通常会出现这种情况。

class A
{
public:
   B* get();
   const B* get() const;
};

我有一个非常量 A 但想运行 get() const 我可能会强制转换。特别是我可能会在非常量本身的实现中这样做。

B* A::get() 
{
   return const_cast<B*>( const_cast< const A*>(this)->get() );
}

当然可以:

B* A::get()
{
    const A* constthis = this; // no need to cast
    return const_cast<B*>(constthis->get());
}

所以我们不必强制转换,但它使第一个解决方案成为单线,无需创建临时变量。

【讨论】:

  • 您可以通过执行相反的操作来避免键入 const_cast&lt;&gt;:根据非常量成员函数实现 const 成员函数。这是因为将T* 转换为T const* 不需要显式转换。
  • @MaximYegorushkin:这将为undefined behaviour land 敞开大门!很抱歉评论晚了,但我认为这个警告很重要。
  • @MatthäusBrandl 当一个对象是非常量时,将其转换为 const 并返回是明确定义的。
  • 也许我读错了你的评论?用非const 来实现const 函数听起来像是抛弃这个常量来调用非常量成员,然后将结果转换回常量。
【解决方案2】:

const_cast,尽管它的名字,并不特定于const;它与有效地包含constvolatilecv-qualifiers 一起使用。

虽然允许透明地添加此类限定符,但删除任何限定符需要const_cast

因此,在您给出的示例中:

char* p = /**/;
char const* q = const_cast<char const*>(p);

const_cast 的存在是虚假的(我个人认为它掩盖了语法)。

但您可以希望删除volatile,在这种情况下您将需要它:

char const volatile* p = /**/;
char const* q = const_cast<char const*>(p);

这可能出现在例如驱动程序代码中。

【讨论】:

    【解决方案3】:

    在您有 f(T*) 和 f(const T*) 的情况下,可能会强制解决重载问题。

    【讨论】:

    • 虽然如果这两个函数做了不同的事情,他们的作者可能应该被打几下。
    • @edA-qa mort-ora-y:将输入复制到临时数据对象是否算作不同的东西?
    • 不同的意思是函数的返回/效果。以不同的方式实现它们是完全合理的,但是这两种形式应该具有相同的最终结果。也就是调用哪一个无关紧要,程序的高层含义不应该改变。
    【解决方案4】:

    您也可以使用static_cast 添加 const。所以我没有看到您必须使用const_cast 来添加const 的任何情况。但是,当您想要更改对象的类型(例如用于重载解析)时,有时可能需要显式转换(无论是一种还是另一种)。

    例如

    void f(char*);
    void f(const char*);
    
    int main()
    {
       char* p = 0;
       f(p); //calls f(char*)
       f(static_cast<const char*>(p)); //calls f(const char*);
       f(const_cast<const char*>(p)); //calls f(const char*);
    }
    

    【讨论】:

    • 如果您只想添加conststatc_cast 使用起来很危险。
    • @Armen Tsirunyan:因为如果有人更改了您要转换的变量的类型,那么转换很可能会无缘无故地将其转换为一些随机且不相关的类型。它使代码更难维护。
    • @Omnifarious:我很抱歉,但这真的没有任何意义。按照同样的逻辑,类型可以更改为添加第二个 const,而 const_cast 将删除它...
    • 假设,当您第一次编写代码时,变量的类型为Derived *。而你static_cast&lt;const Derived *&gt;(v)。然后,稍后,有人将变量的类型更改为Base *。糟糕,static_cast 仍然盲目地进行演员阵容,无论它是否有效。 const_cast 会导致编译器错误。
    • @Armen:不,我同意 Omnifarious。很明显,再次显式写出变量的基本类型会造成不必要的潜在故障点。
    猜你喜欢
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 2016-09-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多