为什么将const变量声明为类成员后仍然可以修改?

5

如果已经赋值的const变量仍然可以被重新赋值,那么它就不是一个const变量了吗?举个例子:

 struct ss
 {
     const int m = 1024;

     ss()
     {
     }

     ss(int m) : m(m)
     {
     }
 };



ss sa;
ss sb(-1);

cout << sa.m << endl;
cout << sb.m << endl; 

哇,m原来不是一个常量!

> /* Ouput:
> 
> 1024
> -1
> 
> */

1
重新分配?你从未重新分配它。 - chris
8
这段代码中没有任何赋值或重新赋值操作,只有初始化。每个变量只会被初始化一次。 - n. m.
3
构造函数初始化列表优先于声明时的初始化,对于不注意的人来说,这似乎是一个不直观的陷阱。 - Matt Coubrough
2个回答

11
 ss(int m) : m(m)
 {
 }

这段话的意思是,在初始化类ss时,使用参数m来初始化其成员m。尽管成员m确实无法被修改,但它可以像其他任何const对象一样进行初始化。请注意,如果我们采用了另一种方式

 ss(int m)
 {
     this->m = m;
 }

那么我们就会有问题,因为 ss::m 需要被初始化。如果 ss::m 是一个具有默认构造函数的类,则在

 ss(FooClass m)
 {
     this->m = m;
 }

不需要显式初始化ss::m,因为它会被默认构造,但是在构造函数中的那行代码会被拒绝,因为它会在ss::m已经被初始化之后修改它。

编辑:哎呀,我误解了你最初的问题。

如此brace-or-equal-initializer将像...

const int m = 1024;

如果成员变量在构造函数初始化列表(ctor-initializer)中未被提及,那么=1024将作为默认值。换句话说,由于默认构造函数没有显式地初始化m,因此使用值=1024。但是ss::ss(int)会显式地初始化m,所以花括号或等号初始化器(brace-or-equal-initializer)会被忽略。


3
你没有解决问题的关键所在,即 const int m = 1024; 这一行。请予以处理。 - user2357112
+1 但是你在最后术语上有错误。mem-initializer 是构造函数初始化列表中的初始化器。非静态数据成员初始化器是 brace-or-equal-initializer - Praetorian

5
你的示例只涉及不同初始化模式,并没有重新赋值。你看到的是构造函数初始化器列表优先于类成员初始化器的效果,我们可以从C++标准草案的第12.6.2初始化基类和成员的第9段中看到:

If a given non-static data member has both a brace-or-equal-initializer and a mem-initializer, the initialization specified by the mem-initializer is performed, and the non-static data member’s brace-or-equal-initializer is ignored. [ Example: Given

struct A {
int i = / some integer expression with side effects / ;
A(int arg) : i(arg) { }
// ...
};

the A(int) constructor will simply initialize i to the value of arg, and the side effects in i’s brace-orequal- initializer will not take place. —end example ]

正如在“C++11成员初始化特性是否使初始化列表过时?”中所讨论的那样,这是一个有用的特性,因为它允许您默认成员变量,然后根据调用的构造函数覆盖这些默认值。


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