最近我看到了这样一个例子:

#include <iostream>

class Foo {
public:
  int bar;
  Foo(int num): bar(num) {};
};

int main(void) {
  std::cout << Foo(42).bar << std::endl;
  return 0;
}

这个奇怪的bar(num)是什么意思?它似乎初始化了成员变量,但我以前从未见过这种语法。它看起来像一个函数/构造函数调用,但int?这对我来说毫无意义。也许有人能启发我。顺便问一下,还有没有其他像这样深奥的语言特性,你在普通的c++书中找不到?


当前回答

你是正确的,这确实是一种初始化成员变量的方法。我不确定这样做有什么好处,除了清楚地表示它是一个初始化。在代码中使用“bar=num”可能更容易被移动、删除或误解。

其他回答

这就是构造函数初始化。这是在类构造函数中初始化成员的正确方法,因为它可以防止调用默认构造函数。

考虑以下两个例子:

// Example 1
Foo(Bar b)
{
   bar = b;
}

// Example 2
Foo(Bar b)
   : bar(b)
{
}

例1:

Bar bar;  // default constructor
bar = b;  // assignment

例2:

Bar bar(b) // copy constructor

这都是效率问题。

还有一个“好处”

如果成员变量类型不支持空初始化,或者它是一个引用(不能被空初始化),那么你别无选择,只能提供一个初始化列表

另一个已经向您解释过,您观察到的语法称为“构造函数初始化列表”。此语法允许自定义初始化类的基子对象和成员子对象(而不是允许它们默认初始化或保持未初始化)。

I just want to note that the syntax that, as you said, "looks like a constructor call", is not necessarily a constructor call. In C++ language the () syntax is just one standard form of initialization syntax. It is interpreted differently for different types. For class types with user-defined constructor it means one thing (it is indeed a constructor call), for class types without user-defined constructor it means another thing (so called value initialization ) for empty ()) and for non-class types it again means something different (since non-class types have no constructors).

在本例中,数据成员的类型为int。Int不是类类型,所以它没有构造函数。对于int类型,此语法仅意味着“用num值初始化bar”,仅此而已。它就是这样直接完成的,不涉及构造函数,因为int不是类类型,因此它不能有任何构造函数。

我不知道你怎么会错过这个,这是非常基本的。这是初始化成员变量或基类构造函数的语法。它既适用于普通的旧数据类型,也适用于类对象。

什么是冒号语法(:)在类构造函数和什么传递一个整数std::vector<>构造函数做?

我想解释下面这个重复问题的例子:

class UnionFind {
    public:
        UnionFind(int sz) : root(sz) {
            for (int i = 0; i < sz; i++) {
                root[i] = i;
            }
        }
    private:
        vector<int> root;
    };
    
    
    int main() {
        
       
        UnionFind uf(10);
    }

冒号(:)表示“初始化列表”或“初始化列表”的开始,它将每个变量初始化为括号中的值。这就好像你在为每个变量调用一个构造函数,将括号中的值传递给该变量的构造函数。

因此,:root(sz)用一个int值sz初始化根变量,这就像执行vector<int> root(sz);。但是,这样做可以将sz传递给UnionFind类构造函数。

用这样的大小初始化一个向量是构造函数#3 (https://en.cppreference.com/w/cpp/container/vector/vector):

// Constructor (3) as shown at
// https://en.cppreference.com/w/cpp/container/vector/vector
explicit vector( size_type count,
                 const T& value = T(),
                 const Allocator& alloc = Allocator());

它在向量中构造了count(在上面的例子中是sz)个数的元素,每个元素的值都是T(),在本例中这意味着int(),因为根是一个<int>的向量。int()看起来像一个函数调用,但实际上是一个值为0(0)的整数默认构造函数。它被称为“值初始化”。把它想象成调用“整数构造函数”,如果整数是对象并且有构造函数的话。在这里也可以看到我的问题:在c++中调用char()作为函数是什么?

所以,让我们回顾一下::root(sz)在构造函数中就像构造vector<int> root(sz);,它在根向量中创建了sz个元素,每个元素的初始值都是int(),这是将int值初始化为0的语法。

还要注意,上面显示的传递给构造函数#3的count参数实际上应该是一个size_type,可以写成std::vector::size_type,通常是size_t(请参阅这里的“成员类型”部分)。因此,将int sz改为size_t sz会更好。因此,将构造函数line: UnionFind(int sz): root(sz){改为:UnionFind(size_t sz): root(sz){。