看看这段非常简单的代码:
struct A { char* s; };
class B
{
A* a;
public: B(const char* s) : a(new A()) {
int len = strlen(s);
a->s = new char[len + 1];
memcpy(a->s, s, len + 1);
}
~B() { delete [] a->s; delete a; }
const char* c_str() const { return a->s; }
const B& to_upper() const {
char* x = a->s;
int len = strlen(x);
for (int i = 0; i < len; i++)
{
char k = x[i];
if (k >= 'a' && k <= 'z')
x[i] -= 32;
}
a->say_hi();
return *this;
}
};
int main() {
B b = "hola mundo";
printf("%s\n", b.to_upper().c_str());
}
有效!!我的问题是......为什么?
to_upper()方法是const,并通过“a”修改值指针。好吧,我无法做“a = nullptr;”之类的事情。因为编译器说:“你正在尝试修改只读对象”;但它让我修改基础价值观。这种行为是否正确?不应该将“a”类型转换为“const A *”,就像在const方法中将“this”的类型转换为“const B *”一样吗?
谢谢!
答案 0 :(得分:6)
方法的常量转换为*this
对象的常量,意味着to_upper
内this
指针的类型为const B *
。这里的所有都是它的。不多也不少。例如,这与您在C语言中看到的效果没有什么不同。它使指针this->a
为const,但它不会影响指针。
实际上,您需要决定B
的常量是否传播到A
指向的this->a
对象。这种语言让您完全自由地做出这个决定。它被称为“概念常数”(与“物理常数”或“逻辑常数”相对)。编译器只观察并强制执行逻辑常量,而OOP中关键字const
的目的远不止于此:它允许您在设计中实现概念常量的概念。
如果A
对象被视为B
的组成部分,则B
的常量也应表示A
的常量。但这是你必须手动观察和执行的东西(或者一些智能指针类可以帮助你解决这个问题。)
如果A
对象是一个独立的对象,恰好只是来自B
的引用,那么B
的常量不一定意味着A
的常量{1}}。
编译器不会对此做出任何决定,因为编译器不知道您尝试实现的对象关系。在您的设计中,我看到它的方式,A
对象实际上是B
的一个组成部分,这意味着您不应该将to_upper
声明为const
}。它是一种修改功能。它将用户感知的内容更改为B
的值。通过将to_upper
声明为const
,您实际上是在向用户撒谎。
答案 1 :(得分:1)
const函数不能修改类成员。 '由a指针'不是该类的成员。