【问题标题】:C++: Initialize a member pointer to null?C ++:将成员指针初始化为null?
【发布时间】:2010-07-07 17:50:42
【问题描述】:

我有一个看起来像这样的类:

class Foo
{
public:
    Foo();
    virtual ~Foo();

private:
    Odp* bar;
};

我希望将bar 初始化为NULL。这是最好的方法吗?

Foo::Foo() : bar(NULL)
{
}

另外,析构函数是否必须是虚拟的? (如果这是真的,那么构造函数也必须是虚拟的吗?)

【问题讨论】:

  • 可以说更好的是Foo::Foo() : bar() {}(注意,不是NULL。)不过最好不要有指针。
  • 为什么这样更好? NULL 是隐含的吗?
  • “为什么这样更好?”您不需要为NULL 的定义包含一个头文件(反正就是0)。 “NULL 是隐含的吗?”是的。 bar() 是一个值初始化;在指针的情况下,它将其初始化为 null。
  • 实际情况稍微少一些,你只需要它是虚拟的,如果: - 有人从你的类继承 - 其他人使用指向你的类的指针来删除该对象即使这样它也只会导致问题,如果该派生类有一个重要的析构函数。因为最后一个很难确定,一般的想法是如果有人从你那里派生出来,你应该使用虚拟析构函数。在这种情况下,派生是 Java 的“扩展”,而不是“实现”。

标签: c++ oop initialization-list


【解决方案1】:

我希望将bar 初始化为NULL。这是最好的方法吗?

这是正确的方式。所以,是的。

另外,析构函数是否必须是虚拟的?

没有。仅当您将从 Foo 类继承并且将使用 Foo 指针删除这些派生类时,析构函数才需要是虚拟的(尽管作为一般经验法则,如果有任何其他类,它应该是虚拟的虚拟会员)。

(如果是这样,那么构造函数也必须是虚拟的吗?)

没有。构造函数不需要virtual,也不能是。

【讨论】:

  • +1 好简洁的答案。我初始化了ctor体内的非常量成员。它使阅读代码更加清晰(关于成员限定符的类型)。
  • @Poni:不,你没有,你重新分配了他们。所有成员都在构造函数主体的开头进行初始化。这就是为什么通常认为在那里“初始化”事物是不好的做法。当然,使用原始类型不会丢失任何内容,但并非所有类型都是原始类型,最好保持一致。当您更多地使用它们并习惯语法时,“清晰”就会出现。
  • MyClass::MyClass() : m_const_var(VALUE) { this->m_non_const_var = OTHER_VALUE }
  • @Poni:你说的我明白了,我想指出m_non_const_var 应该已经在初始化列表中进行了初始化。当您说= OTHER_VALUE 时,您是在分配,而不是在初始化。初始化列表用于初始化。 :) 您的代码会让我怀疑您是否只是不一致,或者是否有某些原因无法初始化这些代码。构造函数主体应该是您运行初始化所需的任何代码的地方,而不是成员。
  • 如果你想通过指向基的指针进行多态删除,析构函数只需要是虚拟的,否则使它成为受保护的和非虚拟的。参见例如Virtuality.
【解决方案2】:
  1. 是的,初始化列表是最好的。

  2. 也许吧。如果您打算在类中拥有任何其他虚函数,或者如果您打算从该类继承(尽管通常这些东西一起出现),则析构函数应该是虚函数。

  3. 没有。在 C++ 中不可能有一个虚拟构造函数。 (这样的事情甚至意味着?)

您问题的性质向我表明您并不真正了解 virtual 关键字的作用或用途,您只是在复制您在其他地方或教程中看到的内容。最好了解您编写的代码的所有的目的。这里可能是一个起点:http://www.parashift.com/c++-faq-lite/virtual-functions.html

【讨论】:

【解决方案3】:

存在四种不同的方式。哪个是最好的取决于你

Foo::Foo() : bar() // value initialization
{
}

Foo::Foo() : bar(0) // direct null pointer constant
{
}

Foo::Foo() : bar(NULL) // null pointer constant by macro
{
}

Foo::Foo() : bar(nullptr) // pointer literal of type std::nullptr_t
{
}

【讨论】:

  • 现在Foo::Foo(): bar(nullptr){}
【解决方案4】:
  1. 是的
  2. 关于析构函数是虚拟的第二个问题,请参阅:http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.7 简短的回答,在你的情况下,没有析构函数不是必需的。
  3. 没有虚拟构造函数之类的东西。

【讨论】:

    【解决方案5】:

    您可能要考虑的另一个选项是使用智能指针类(例如boost::scoped_ptrboost::shared_ptr 或 C++0x 的unique_ptr)而不是原始指针。如果您不需要其他显式初始化,智能指针的构造函数将确保将其初始化为类似 NULL 的内容。智能指针也会确保指向的对象被销毁。

    您只需要确定适合该项目的智能点策略并相应地选择(只要您了解各种陷阱,即使auto_ptr 可能比原始指针更好)。

    【讨论】:

      【解决方案6】:

      1,是的

      2,仅当您希望某人能够从您的类派生并使用指向基类的指针 - 但无论如何都要使 dtor 虚拟

      3,不,您不能拥有虚拟 ctor(或者我想所有的 ctor 都是虚拟的?)

      【讨论】:

      • "所有 ctors 都是虚拟的" - 不,在编译时决定调用哪个构造函数。 “虚拟”意味着运行时决策。
      【解决方案7】:

      虚拟函数用于确定在运行时必须调用类的哪个函数(在基类和派生类中都定义)。但是当创建对象时,编译器知道要调用哪个构造函数。例如。当创建基对象时,基构造函数被调用,派生类也是如此。因此,将构造函数设为虚拟没有任何意义。但是一旦基类对象指针指向派生类对象,然后调用析构函数,编译器就会混淆需要调用哪个析构函数(基类或派生类),即只能使用查找表 vtable 解决,因此析构函数需要是虚拟的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-06
        • 1970-01-01
        • 2012-07-18
        • 2010-10-16
        • 1970-01-01
        • 2012-02-13
        • 1970-01-01
        相关资源
        最近更新 更多