【问题标题】:Partial const typecast in C++C++ 中的部分 const 类型转换
【发布时间】:2015-03-13 18:38:54
【问题描述】:

有时,在传递或返回结构时,可能需要将某些字段设为 const:

struct A
{
   char c;
   int x;
};

struct B
{
   const char c;
   int x;
};

void process(B& b)
{
   if(b.c=='1')
      b.x++;
}

void test()
{
   A a;
   a.c = '1';
   a.x = 0;
   process(reinterpret_cast<B&>(a));
}

这种部分 const 类型转换是否足够便携和安全?

【问题讨论】:

  • 我们可以做一些类似process(reinterpret_cast&lt;B&amp;&gt;(const_cast&lt;A&amp;&gt;(a))); 的事情,它会起作用看到这个ideone.com/xnblvi

标签: c++ struct casting constants partial


【解决方案1】:

正如 Wojtek 所指出的。由于在 2 种不同类型之间进行强制转换,显然不安全,不应该使用。但正如我在评论中提到的,出于演示目的,我们可以针对这种特殊情况进行类型转换的链接。

首先在 A 的对象中添加 constness,然后使用 reinterpret_cast

struct A
{
   char c;
   int x;
};

struct B
{
   const char c;
   int x;
};

void process(B& b)
{
   if(b.c=='1')
      b.x++;

      cout<<b.x;
}


void  test() {
    // your code goes here
    A a;
   a.c = '1';
   a.x = 3;
   process(reinterpret_cast<B&>(const_cast<A&>(a))); //first add constness to A's data and then use reinterpret_cast

}

在这里演示。http://ideone.com/xnblvi如果有人发现任何问题,请发表评论。

【讨论】:

  • 向 A 添加 const 使其所有字段都为 const,我们需要第二个字段为非 const,因此将使用 将其转换回非 const。
  • 是否有另一种方法可以限制修改某些结构成员而不使用 reinterpret_cast?也许,只是将它们分成单独的参数,但这比我上面提到的方法更容易出错。
  • @bkxp 恐怕会产生其他问题。我找到的最小紧凑解决方案只有这个。
【解决方案2】:

仅对您代码中的示例是安全的。 一般来说,该技术并不安全。

a.c 在声明时不是常量,所以 B.c 会继承 c 的值,而 c 的 constness 将仅用于强制语法。

如果反过来,就会出现问题:

B b;
b.c = '1';
b.x = '0;
process(reinterpret_cast<A&>(b));

原因是 b.c 会在声明时被分配给一个常量,并且尝试更改 a.c 可能会导致未定义的行为,因为您最终可能会从只读空间更改变量。

【讨论】:

  • 为什么?如果 B 是 const 则我们可以通过 const_cast 删除 constness
  • 您可以使用 const_cast 删除对象的一致性,但如果该对象在声明时是常量,则它可能最终进入只读内存。一个更好的例子是使用字符串。 const char* str = "你好"; .您可以 const cast str ,但如果编译器将字符串“Hello”放置在程序的只读内存中,则尝试更改指向 str 的任何内容将导致未定义的行为(很可能是崩溃)。
  • 指针和引用更明显。在 OP 的示例中,只有值。操作员询问该技术本身是否安全:仅对于该示例是安全的,但在一般情况下使用任何类型的变量都不安全!
  • MichaelCMS,编译器不允许创建 B b;无需初始化其 const 字段。此外,它不允许为 b.c 分配任何东西(仅对其进行初始化),还会出现另一个编译器错误。至于反向 reinterpret_cast,这类似于创建 const int 变量,然后在将其作为 int& 传递到某处之前对其进行 const_casting。
【解决方案3】:

没有这样的技术是不安全的,它是未定义的行为 - 在不相关的类型之间进行转换,即使它们看起来相似,也绝不是安全的。

【讨论】:

  • “安全”是指如果 X 和 const X 字段总是以相同的方式在结构中表示。它们应该是,因为我们可以创建指向单个字段的 const 指针并将它们与指向相同字段的非常量指针进行比较,这是安全的。唯一不安全的是必须同时更改 A 和 B。
  • @bkxp 当然,您可以创建指向各个字段的指针并进行比较。这并不意味着整个结构是等价的。 (比如说,一个疯狂的编译器在调试版本的const 成员之前添加了一些隐藏成员以用于调试目的)。在 C++ 标准中找不到任何支持这种类型转换的东西。 reinterpret_cast 的合法用途很少,这不是其中之一。
  • 在某些情况下,您可能需要限制对某些数据成员的写入。你会使用什么方法?使用 getter 和 setter 编写一个接口类,并将对它的引用传递给 process() 方法?
  • @bkxp 你的建议是可能的。在您提供的示例中,您甚至可以拥有没有 setter 的基类和带有它的派生类。 process 函数将接受基类。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-08-06
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2020-06-09
  • 2014-10-26
  • 1970-01-01
相关资源
最近更新 更多