1
template<class T>
Queue<T>::Queue(): frontPtr(NULL), backPtr(NULL), count(0)
{
}

为什么是它Queue():而不只是Queue()

4

3 回答 3

4

正如其他人评论的那样,这:表明存在初始化列表。您可以在您最喜欢的 C++ 书籍或许多优秀网站中找到更多信息;一个快速的谷歌搜索给了我这篇似乎写得很好的文章:http ://www.cprogramming.com/tutorial/initialization-lists-c++.html 。

如果您想要初始化器列表的简短执行摘要,请参考:初始化器列表可以包含对基类构造函数的调用和对成员变量构造函数的调用。

你为什么想要这样的东西?嗯,很多原因。


请注意,代码相当简单,并且包含一些愚蠢(例如Name类)。目的只是为了展示初始化列表是如何工作的,而不是编写花哨的代码或利用所有可能的 C++ 特性。


基类的构造

想象一下,你有一个基类,它需要一些参数才能被构造。没有其他方法可以将必要的参数传递给它的构造函数,因为当{打开构造函数的主体时“执行”(请原谅在这种情况下有点松散地使用“执行”),基类已经被构造:

class Name
{
    const char *name;

public:
    Base(const char *n)
    {
        name = n;
    }

    const char *getName() const
    {
        return name;
    }
};

class Derived : public Name
{
    int a;

public:
    Derived(int x)
        : Name("Derived")
    {
        a = y;
    }

    // Without the call to Name("Derived") in the constructor initializer
    // list how could you possibly initialize the base class here?
};

作为类实例的成员的构造

同样,也许您的类成员具有需要参数的构造函数。问题是类似的:你可以在哪里调用这些构造函数来传递参数以及如何调用?答案在初始化列表中。让我们扩展我们之前的示例:

class Name
{
    const char *name;

public:
    Base(const char *n)
    {
        name = n;
    }

    const char *getName() const
    {
        return name;
    }
};

class MyInt
{
    int value;

public:
    MyInt(int i)
    {
        value = i;
    }

    int getInt() const
    {
        return value;
    }
}

class Derived : public Name
{
    MyInt a;

public:
    Derived(int x)
        : Name("Derived"), a(x)
    {

    }

    // Without the call to a(x)  in the constructor initializer
    // list how could you possibly initialize that member variable 
    // here?
};

有效地初始化成员变量

当您通过将变量放在赋值的左侧手动设置变量时,您实际上并没有“初始化”它。您正在执行一项任务。

这可能是一个有点深奥的区别,但它有许多重要的含义。其中之一(甚至不是最重要的)是性能。

由于在 C 中,所有基类的构造函数和所有成员变量都必须在构造函数主体开始执行之前完成,这可能意味着将在其中一个构造函数中完成大量工作。当您为这些成员变量之一分配新值时,所有这些工作都可能丢失。

因此,您可以通过在构造函数初始化程序列表中传递必要的值来初始化成员变量(不管它们的类型)。让我们重新编写上一个示例:

class Name
{
    const char *name;

public:
    Base(const char *n)
        : name(n)
    {
        // notice that at this point the member variable "name"
        // has already been initialized and can be accessed. 
    }

    const char *getName() const
    {
        return name;
    }
};

class MyInt
{
    int value;

public:
    MyInt(int i)
        : value(i)
    {
        // Again, note here that the variable "value" already contains
        // its value. We need not initialize it again.
    }

    int getInt() const
    {
        return value;
    }
}

class Derived : public Name
{
    MyInt a;

public:
    Derived(int x)
        : Name("Derived"), a(x)
    {

    }
};

观察我们如何移动事物的初始化。尽管我们的程序工作方式相同,但它现在的行为却大不相同。要了解原因,让我们添加另一个类:

class Name
{
    const char *name;

public:
    Base(const char *n)
        : name(n)
    {
        // notice that at this point the member variable "name"
        // has already been initialized and can be accessed. 
    }

    const char *getName() const
    {
        return name;
    }
};

class MyInt
{
    int value;

public:
    MyInt(int i)
        : value(i)
    {
        // Again, note here that the variable "value" already contains
        // its value. We need not initialize it again.
    }

    int getInt() const
    {
        return value;
    }
}

class Example : public MyInt
{
    const char *type;

public:
    Example()
        : MyInt(0), type("default")
    {
    }

    Example(int x)
        : MyInt(x), type("custom")
    {
    }

    const char *getType() const
    {
        return type;
    }
}

class Derived : public Name
{
    Example a;
    Example b;

public:
    Derived(int x)
        : Name("Derived"), a(x)
    {

    }

    void print()
    {
        std::cout << "This is an " << getName() << " instance" << std::endl;
        std::cout << "  a has a " << a.getType() << " value" << std::endl;
        std::cout << "    a=" << a.getInt() << std::endl;
        std::cout << "  b has a " << b.getType() << " value" << std::endl;
        std::cout << "    b=" << b.getInt() << std::endl;
    }
};

int main(int argc, char **argv)
{
    Derived d;

    d.print(123);

    return 0;
}
于 2013-10-30T01:41:24.237 回答
3

冒号表示initializer list您的构造函数。
它使您能够对类的成员变量进行值初始化。

以下大致相似(但效率低于Initializer List):

template<class T>
Queue<T>::Queue()
{
 frontPtr = NULL;
 backPtr = NULL;
 count = 0;
}
于 2013-10-30T01:05:39.570 回答
-3

这个:

template<class T>
Queue<T>::Queue(): frontPtr(NULL), backPtr(NULL), count(0)
{
}

达到与以下大致相同的目的:

template<class T>
Queue<T>::Queue()
{
    frontPtr = NULL;
    backPtr = NULL;
    count = 0;
}

有一些重要的区别,包括:

  • 使用初始化列表,您不会将其构造和初始化为两个单独的操作;
  • const使用初始化列表是初始化成员变量的唯一方法。
于 2013-10-30T01:10:11.250 回答