8

我主要是 ac# 程序员,但我正在从事的一个项目让我使用 c++。在 C# 中,我能够定义一个类的成员,该成员在初始化之前为空。像这样:


Class Foo{
    private Bar _bar;
    public Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
}

的价值_barnull 并且在初始化之前禁止访问。这个用例的基本原理是私有对象的构造函数依赖于一些在构造父类之前不知道的值。

现在,在 C++ 中,我尝试做同样的事情:


class Foo{
public:
    Foo(int valueBarNeeds){
        _bar = new Bar(valueBarNeeds);
    }
private;
    Bar _bar;
};

编译器抛出一个错误,指出没有接受零参数的 bar 构造函数。我的理解是,在 C++ 中,new关键字意味着完全不同的东西。new作为这种差异的一部分,可以通过不带关键字的声明来定义在方法末尾处理的对象,而无需手动删除。


SomeFunc(){
    int valueBarNeeds = 100;
    Bar _bar(valueBarNeeds);
    _bar.SomeFunc();
}

_bar当方法堆栈超出范围时被删除。

这就提出了我的问题。如果我在 C# 中用于创建单元化对象的语法实际上试图在 C++ 中初始化对象...如何创建可由父对象构造函数构建的其余类方法可访问的单元化类型?

4

2 回答 2

6

问题是你所说的“初始化”实际上不是这样的。在程序进入您的构造函数体之前,任何已初始化、隐式或显式初始化的成员都会被初始化。

您的代码片段仅显示assignment;在封装对象的构造函数主体中执行此操作并不重要。它仍然只是任务。

Bar是一个类,因此您的成员_bar 被隐式初始化,但实际上不可能是因为该类没有不带参数的构造函数。为了提供参数,您必须自己显式初始化成员。

在 C++ 中,我们像这样初始化成员:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(valueBarNeeds)
    {}
private:
    Bar _bar;
};

你也是对的,你误解new了一点。与 Java 不同,它应该谨慎使用,因为对象基本上是通过简单地声明(并在必要时定义)它们来创建的。的使用new是为free store中的动态分配保留的,并返回一个指针供使用;这种用法应该很少见。您在最终的代码片段中成功地修复了这个问题。

如何创建可由父对象构造函数构建的其余类方法可访问的统一类型?

如果成员是类类型,它将始终被初始化。你不能有一个不存在的对象。您可以获得的最接近的是封装指针而不是对象:

class Foo {
public:
    Foo(int valueBarNeeds)
     : _bar(nullptr)
    {
       // some time later...
       _bar = new Bar(valueBarNeeds);
    }
private:
    Bar* _bar;
};

但这会在内存管理和诸如此类的方面打开一大堆蠕虫,并且如上所述,除非您真的需要它,否则您应该避免它。替代方案包括智能指针,但您仍应考虑尽可能坚持使用沼泽标准对象封装。您很少需要故意将对象置于无效状态一段时间。

于 2013-11-10T22:51:00.060 回答
3

你给你的类一个该类型的数据成员,并在构造函数的初始化列表中初始化它:

class Foo
{
 public:
     Foo(int valueBarNeeds) :_bar(valueBarNeeds) {}
 private:
     Bar _bar;
};

一旦进入构造函数的主体,所有数据成员都已初始化。如果你没有在构造函数初始化列表中显式地初始化它们,它们会被默认初始化,这意味着默认构造函数被用户定义的类型调用,并且不为内置类型执行初始化。

于 2013-11-10T22:51:39.327 回答