6

我是否正确假设 C 风格的演员表(不鼓励)只不过是 reinterpret_casts ?在寻找讨厌的演员表时,使用后者在视觉上很引人注目并且易于搜索,因此建议使用 C 风格的演员表?

如果使用 const_cast 丢弃 const 并写入最初的 const 对象是未定义的,那么 const_cast 的目的是什么?

注意:我知道 Bjarne 正确地谴责铸造操作是不安全的,甚至到了“丑陋的操作应该有丑陋的句法形式”的程度。因此在 C++ 中强制转换运算符的冗长。所以我会尽量减少它们的使用。承诺。:)

4

5 回答 5

5

不会。 AC cast 可以做相当于 a const_cast、 a static_cast、 areinterpret_cast或它们的组合。如果这还不够,它还可以完成至少一个新演员组合根本无法做到的小技巧!

如果原始变量没有定义,则可以使用const_castwith defined results const,但您所拥有的只是const对该对象的指针或引用。OTOH,如果您认为自己有充分的理由使用 a const_cast,那么您很可能应该真正抬头mutable

编辑:我想我应该马上说出来,但是 C 风格的转换可以转换为一个不可访问的基类。例如,考虑以下内容:

[编辑:我将代码更新为可以编译和(通常)演示问题的代码。]

#include <iostream>

class base1 {
public:
    virtual void print() { std::cout << "base 1\n"; }
};

class base2 {
public:
   virtual void print() { std::cout << "base 2\n"; }
};

class derived : base1, base2 {}; // note: private inheritance

int main() {    
    derived *d = new derived;
    base1 *b1 = (base1 *)d;    // allowed
    b1->print();    // prints "base 1"
    base2 *b2 = (base2 *)d;    // also allowed
    b2->print();    // prints "base 2"

//    base1 *bb1 = static_cast<base *>(d);  // not allowed: base is inaccessible

    // Using `reinterpret_cast` allows the code to compile.
    // Unfortunately the result is different, and normally won't work. 
    base1 *bb2 = reinterpret_cast<base1 *>(d);
    bb2->print();   // may cause nasal demons.

    base2 *bb3 = reinterpret_cast<base2 *>(d); 
    bb3->print();   // likewise
    return 0;
}

使用reinterpret_casts 的代码将编译 - 但尝试使用结果(至少两者之一)将导致重大问题。reinterpret_cast获取派生对象的基地址并尝试将其视为指定类型的基对象——并且由于(至多)一个基对象实际上可以存在于该地址,因此尝试将其视为另一个可以/将导致重大问题。编辑:在这种情况下,除了打印的内容之外,这些类基本上是相同的,所以尽管任何东西都可以发生,对于大多数编译器,最后两个都会打印出“base 1”。reinterpret_cast 获取该地址中发生的任何内容并尝试将其用作指定的类型。在这种情况下,我(试图)让它做一些无害但可见的事情。在实际代码中,结果可能不会那么漂亮。

如果代码使用公共继承而不是私有继承,C 风格的强制转换将像 static_cast 一样工作——即它知道每个基类对象在派生类中“存在”的位置,并调整结果,因此每个结果指针都会工作,因为它已被调整为指向正确的位置。

于 2010-02-27T08:16:05.073 回答
1

不,C 风格的强制转换可以根据情况充当reinterpret_casts、const-casts 或static_casts。这就是他们不鼓励的原因——你在代码中看到了 C 风格的转换,需要寻找细节来看看它会做什么。例如:

const char* source;
int* target = (int*)source;// - acts as const_cast and reinterpret_cast at once
//int* target = retinterpret_cast<int*>source;// - won't compile - can't remove const
于 2010-02-27T08:14:44.993 回答
1

请记住,一个 const cast 可能作用于原始标识符以外的其他东西:

void doit(const std::string &cs)
{
    std::string &ms = const_cast<std::string &>(cs);
}

int main()
{
    std::string s;
    doit(s);
}

因此,虽然 doit 正在抛弃 const,但在此示例中,底层字符串不是 const,因此没有未定义的行为。

更新

好的,这是一个更好的例子,说明使用 const_cast 并非完全没有价值。我们从一个带有 const 参数的虚函数的基类开始:

class base
{
public:
    virtual void doit(const std::string &str);
};

现在您要覆盖该虚拟功能。

class child : public base
{
public:
    virtual void doit(const std::string &str)
    {
        std::string &mstr = const_cast<std::string &>(str);
    }
};

由于代码的逻辑/结构,您知道child::doit只会使用非常量字符串调用它(并且class base不受您的控制,因此您不能修改它也不能更改签名,child::doit因为那样它就不会再覆盖base::doit)。在这种情况下,丢弃 const 是安全的。

是的,这是有风险的。也许当您编写该代码时,确实不会child::doit使用非常量字符串执行执行并且代码是有效的。但这可能会在维护您的程序时发生变化,或者在您重建并选择最新版本的class base.

于 2010-02-27T08:17:20.050 回答
0

const_cast用于const从类型中删除。它还可以删除volatile. 如果对象真的是,const那么结果不能被写入并且仍然是明确定义的行为。但是,如果它被提升为const(通过传递给一个const T函数,然后const_cast将它返回到 non-就可以了。(我在这里const找到了更多信息)

reinterpret_cast 不能从类型中删除const或删除。volatile

也可以看看

于 2010-02-27T08:13:00.213 回答
0

C 风格的演员表真的是编程的大锤——你基本上告诉编译器那边的方钉无论如何都可以穿过这个圆孔。从这个意义上说,reinterpret_cast非常相似。

我在使用 C++ 风格的强制转换运算符时看到的主要优点是它们允许您更好地表达您的意图并允许编译器仍然对您要求它执行的操作进行一些检查,而不是一刀切-所有风格C演员。

关于const_cast- 您经常遇到通过 const 引用传递对象的情况,这仅仅是因为 API 要求您这样做。比如说,你有一个函数 X 来处理一个 C 风格的字符串:

void X(const char *str) { ... }

在该函数内部,您将参数传递给需要 a 的 C 函数char *,即使它没有更改字符串。适应这种情况的唯一方法是const_caststr.

我会非常小心地使用任何类型的演员表,这通常表明您的设计有些地方不太正确,但有时您必须说服编译器它正在查看的挂钩并不像它假设的那样方形。只有这样你才应该使用强制转换运算符。

于 2010-02-27T08:15:28.803 回答