如何在构造函数中初始化常量字段?

82

假设我有一个C++类Foo和一个类Bar,必须使用构造函数创建,其中传递了一个Foo指针,并且该指针在Bar实例的生命周期中应保持不可变。正确的做法是什么?

实际上,我认为可以编写下面的代码,但它无法编译...

class Foo;

class Bar {
public:
    Foo * const foo;
    Bar(Foo* foo) {
        this->foo = foo;
    }
};

class Foo {
public:
  int a;
};

欢迎提出任何建议。

6个回答

103
你需要在初始化列表中完成它:
Bar(Foo* _foo) : foo(_foo) {
}

(请注意,我重命名了传入变量以避免混淆。)


3
+1,虽然我最近在这里了解到以下划线开头的变量现在官方上是被保留的 ;) - Michael Krelin - hacker
2
只有在它们后面跟着一个大写字母时才成立。 - GManNickG
2
或者在命名空间范围内!或者后面跟着另一个下划线。所以,是的,在这种情况下技术上是合法的,但我会建议更容易的方法是假装它们是保留的,不要使用它们。 :) - jalf
3
我喜欢jalf,即使这违法。 - Michael Krelin - hacker
21
关于重命名,这是少数几个在表达式中可以使用相同名称但具有不同含义的地方之一:'Bar(Foo* foo) : foo(foo) {}' 可以正常工作,因为在初始化列表中第一个foo必须是基类或当前类的属性,但在括号内部参数会隐藏属性,因此那里的'foo'是传入的参数。 - David Rodríguez - dribeas
显示剩余8条评论

24

我认为你必须在初始化器中完成它。例如:

Bar(Foo* foo) : foo(foo) {
}
作为一个旁注,如果你永远不会改变foo指向的内容,将其作为引用传递进来:
Foo& foo;

Bar(Foo& foo) : foo(foo) {
}

4
+1:在你需要的地方使用指针,在你想要的地方使用引用。 - David Rodríguez - dribeas
如果你永远不会改变它所指向的内容,那么NULL不是一个有效的条件! - David V. Corbin
@DavidV.Corbin 嗯,你可以在构造函数中检查那个 NULL 值并抛出适当的异常。 - Tom Lint
@TomLint - 我所指的是在设计参数时使用指针或引用的选择。不是关于“你可以做什么”(C++有意允许你“炸掉整个腿”),而是关于“认知负荷”(易于理解)...如果我看到一个声明采用指针,我会问“在哪些情况下将NULL传递给此方法参数是合适的?”如果我看到它采用引用,所有我花费在思考传递null的影响上的时间都将为其他活动节省。 - David V. Corbin

18

在初始化列表中可以完成对常量成员和其他特殊情况(如父类)的初始化。

class Foo {
private:
   const int data;
public:
   Foo(int x) : data(x) {}
};

或者,同样地,对于父级初始化

class Foo {
private:
   int data;
public:
   Foo(int x) : data(x) {}
};

class Bar : Foo {
public:
   Bar(int x) : Foo(x) {}
};

6

你需要在初始化列表中初始化foo。

class Bar {
    Foo* const foo;
  public:
    Bar(Foo* f) : foo(f) {...}
};

0

使用引用:

Foo& foo;
Bar(Foo& f) : foo(f) { }

然后你可以在 Bar 中轻松地引用 foo

foo.doSomething();

2
我投票为“否定”,因为如果它是唯一的答案,我可能会错误地认为使用引用是实现它的唯一方法,而另一个答案显示的是,关键在于初始化列表。 - puccio
在我看来,引用在这种情况下更加优雅,因为指针在初始化后不必改变 :) - Khaled Alshaya
@hacker 我只是说出了我认为更好的做法。 - Khaled Alshaya
1
我认为这个答案被低估了。如果你想引用一个对象并且所引用的对象的地址永远不会改变,那么引用比const指针要好得多。另一方面,也许你想指向一个const对象?那是另外一回事,有稍微不同的语法。 - Spacemoose

0

尝试: Bar(Foo* xfoo) : foo(xfoo) {}


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