如何在C++中将指向Foo**的指针转换为const Foo**?

8

I have

class Fred 
{
public:
  void inspect() const {}; 
  void modify(){};
};

int main()
{
 const Fred x = Fred();
 Fred* p1;
 const Fred** q1 = reinterpret_cast<const Fred**>(&p1);
 *q1 = &x; 
 p1->inspect();
 p1->modify();
}

如何通过指针转换实现const Fred ** q1 =&p1?

(我刚刚读到可能可以实现这一点)

感谢你们的回答。 const_cast确实适用于对象。

#include <iostream>
#include <stdio.h>
using namespace std;

class Fred 
{
 int a;

public:
Fred(){};
Fred(int a_input)
{
 a = a_input;
};

void inspect() const 
{
 cout << "Inspect called"<< endl;
 cout << "Value is ";
 cout << a << endl;
}; 

void modify()
{
 cout << "Modify called" << endl;
 a++;
};

};

int main()
{
 const Fred x = Fred(7);
 const Fred* q1 = &x;
 Fred* p1 = const_cast<Fred*>(q1); 
 p1->inspect();
 p1->modify();
 p1->inspect();
 x.inspect();
 *p1 = Fred(10);
 p1->inspect();
}

提供

Inspect called
Value is 7
Modify called
Inspect called
Value is 8
Inspect called
Value is 8
Inspect called
Value is 10
Inspect called
Value is 10

然而,对于预定义类型,它无法起作用:

int main()
{
 const double a1 = 1.2;
 const double* b1 = &a1;
 cout << "a1 is " << (*b1) << endl;
 cout << "b1 is " << b1 << endl;
 double* c1 = const_cast<double*>(&a1);
 cout << "b1 is " << b1 << endl;
 cout << "c1 is " << c1 << endl;

 double* d1 = static_cast<double*>(static_cast<void*>(c1));
 cout << "d1 is " << d1 << endl;
 cout<< "*d1 is " << *d1 << endl;

 *d1=7.3;

 cout<< "*d1 is " << *d1 << endl;
 cout<< "*d1 address is "<< d1 << endl;
 cout << "a1 is " << a1 << endl;
 cout << "a1 address is" << &a1 << endl;
 cout<< "*d1 is " << *d1 << endl;
 cout<< "*d1 address is "<< d1 << endl;

 double f1=a1;
 printf("f1 is %f \n", f1);
}

导致的结果是:
a1 is 1.2
b1 is 0xffbff208
b1 is 0xffbff208
c1 is 0xffbff208
d1 is 0xffbff208
*d1 is 1.2
*d1 is 7.3
*d1 address is 0xffbff208
a1 is 1.2
a1 address is0xffbff208
*d1 is 7.3
*d1 address is 0xffbff208
f1 is 1.200000 

显然,g++编译器进行了优化,每当它发现a1时,就将其替换为1.2,因此,即使在堆栈上它的值已更改,它也不会关心。

(在我的情况下,我直接读取*b1、*c1会出问题,所以我必须进行双重静态转换 - reinterpret cast无法工作)。

有没有办法真正改变a1,在“正常”编译的情况下进行编译,因此不要进行优化(以免受到优化效果的影响)?


1
感谢重新格式化!阅读起来更容易了! - Toji
1
你新增的信息实际上是一个不同的问题。将来请考虑单独发布它(这样它会得到更多的答案)。至于const原始类型的编译器优化:如果你不想让编译器进行优化,那么...就不要将其设置为const。const的目的是告诉编译器你不会改变该值。因此,如果你之后试图更改它,你就违反了C++标准。换句话说,不要这样做!再次强调,如果你打算更改一个值,请不要将其设置为const。没有例外。 - Toji
6个回答

17

这应该可以解决:

Foo** f;
const Foo** cf = const_cast<const Foo**>(f);

11

这不是一个好主意,因为它违反了类型安全。让我解释一下为什么:

Fred* pFred;
const Fred** ppFred = const_cast<const Fred**>(&p);

*ppFred = new const Fred;  // Now pFred points to a const Fred

pFred->some_evil_mutating_method(); // can do, since type of *pFred is non-const!

2
你在警告避免这种行为上是正确的,但请不要将“不是好主意”与“不可能”混淆。在他的代码中使用 const_cast 替换 reinterpret_cast 可生成完全有效、可编译的 C++ 代码。 - Toji
2
是的,我刚刚检查了标准。我的错 - 我从未意识到const_cast尽管本质上不安全,但在指针链中是明确定义的。具有讽刺意味的是,人们普遍认为const_cast只有在从固有const的对象中去除constness时才不安全 - 而在这种情况下,当您向非const对象“添加”const时,它是不安全的。对我来说,这看起来是一个非常臭的设计决策,但我想这就是C++。我会修复答案。 - Pavel Minaev
@Pavel,如果你需要使用const_cast,那么你可能正在做一些潜在的危险操作,安全的情况下不需要进行强制转换。(请注意,在C语言中,有些安全情况确实需要进行转换)。 - AProgrammer
1
我认为AProgrammer在使用const_cast时是想要移除const。如果要添加const,可以使用其他方法代替强制转换,例如A const& a = *thus; a.doit(); - Johannes Schaub - litb
你可以这样做,尽管我不认为有必要引入额外的本地变量,因为已经有一个专门用于此目的的转换。 :) - Pavel Minaev
显示剩余2条评论

3

允许您创建一个指向const对象的非const指针,但任何试图实际更改该const对象的尝试仍会导致未定义的行为。 - Ben Voigt

1
为什么不直接制作:?
const Fred** q1;
*q1 = p1;

或者你想在没有使用const_cast的情况下避免constness违规吗?——不行,先生,你不能这样做。


0

你不应该这样做。你不能轻易地进行转换的事实是因为它会破坏常量正确性(并且你的代码会执行它)。使用上面的建议,你的代码将编译并在一个常量对象上调用一个变异方法(代码的最后一行)。

这是不推荐的,在一些罕见的情况下甚至可能会导致应用程序崩溃(一个常量全局对象可能存储在只读内存页中),或者使其处于不稳定的状态(通过更改常量引用到内部成员元素来更改对象的内部状态,从而破坏对象不变式)。

关于你的问题:C++ FAQ Lite [18.17]


-1

对于const Fred** q1 = &p1,你不需要进行任何转换,因为非常量的Fred **可以直接赋值给一个带有const Fred ** q1的声明。


1
不行,它做不到。你可以自己试试看 - 如果没有 const_cast 它是无法编译的。 - Pavel Minaev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接