【问题标题】:Creating an instance of class创建类的实例
【发布时间】:2012-08-28 05:46:33
【问题描述】:

第 1、2、3、4 行有什么区别?

我什么时候使用它们?

为什么第 3 行打印 constructor Foo 而第 7 行返回错误而第 8 行没有?

#include <iostream>     
using namespace std;

class Foo
 {
   public:
   Foo ( )
   {
      cout << "constructor Foo\n";
   }               
};

class Bar
 {
   public:
   Bar ( Foo )
   {
      cout << "constructor Bar\n";
   }
};

int main()
{
   /* 1 */ Foo* foo1 = new Foo ();
   /* 2 */ Foo* foo2 = new Foo;
   /* 3 */ Foo foo3;
   /* 4 */ Foo foo4 = Foo::Foo();

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );
   /* 6 */ Bar* bar2 = new Bar ( *new Foo );
   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );
   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

   return 1;
}

【问题讨论】:

  • 无论你做什么,不要做*new Foo。这是一个即时的内存泄漏。 Avoid new unless you really really need it.
  • 对我来说看起来很家庭作业
  • 我只有一本关于 C++ 的书,并且没有在其中讨论这个主题...
  • 您确实意识到您的编辑使 2 个答案过时了,对吧?另外,它是无效的...... 5 和 6 提供了该做什么的很好的例子。他们在那里还不错。
  • 你应该添加 Foo foo5();在列表中。

标签: c++ class constructor


【解决方案1】:
   /* 1 */ Foo* foo1 = new Foo ();

在动态内存中创建Foo 类型的对象。 foo1 指向它。通常,您不会在 C++ 中使用原始指针,而是使用智能指针。如果Foo 是 POD 类型,这将执行值初始化(此处不适用)。

   /* 2 */ Foo* foo2 = new Foo;

与之前相同,因为Foo 不是 POD 类型。

   /* 3 */ Foo foo3;

在自动存储中创建一个名为 foo3Foo 对象。

   /* 4 */ Foo foo4 = Foo::Foo();

使用复制初始化在自动存储中创建一个名为foo4Foo 对象。

   /* 5 */ Bar* bar1 = new Bar ( *new Foo() );

使用Bar 的转换构造函数在动态存储中创建Bar 类型的对象。 bar1 是指向它的指针。

   /* 6 */ Bar* bar2 = new Bar ( *new Foo );

和以前一样。

   /* 7 */ Bar* bar3 = new Bar ( Foo foo5 );

这只是无效的语法。你不能在那里声明一个变量。

   /* 8 */ Bar* bar3 = new Bar ( Foo::Foo() );

如果bar3 未在 7 中声明,则将按照与 5 和 6 相同的原则工作。

5 & 6 包含内存泄漏。

new Bar ( Foo::Foo() ); 这样的语法并不常见。通常是new Bar ( (Foo()) ); - 额外的括号说明最麻烦的解析。(已更正)

【讨论】:

  • 实际上,Foo::Foo() 是否合法?我以为不是。
  • 类似 new Bar ( Foo::Foo() ); 的语法并不常见。通常是new Bar ( (Foo()) ); 但是这个范围内的两个类有一个Foo 方法是什么?
  • 虽然new 表达式中不会发生最令人头疼的解析;)
  • @KonradRudolph:是的,这是合法的。语言确定类型的名称被注入到类型的定义中,因此任何数量的嵌套Foo::Foo::..::Foo() 都将解析为完全相同的东西:Foo()。这是简化语言以允许神秘代码的情况之一。
  • @Kolyunya:我不明白你的担心,你能解释一下:什么是这个范围内的两个类有一个Foo 方法? Foo::Foo 是一个复杂的键入Foo() 的方式,它是一个类型的名称和一组括号。查找只能返回具有特定名称的 一个 类型——尽管如果在遇到该类之前通过查找找到名为 Foo 的函数,则会调用该函数,但这是正交的解决手头的问题。
【解决方案2】:
  1. 从空闲存储中分配一些动态内存,并使用其默认构造函数在该内存中创建一个对象。你永远不会删除它,所以内存泄漏了。
  2. 与 1 完全相同;对于用户定义的类型,括号是可选的。
  3. 分配一些自动内存,并使用其默认构造函数在该内存中创建一个对象。当对象超出范围时,内存会自动释放。
  4. 类似于3。名义上,命名对象foo4是通过默认构造、复制和销毁临时对象来初始化的;通常,这会被省略,得到与 3 相同的结果。
  5. 分配一个动态对象,然后通过复制第一个对象来初始化第二个对象。两个对象都泄漏了;并且没有办法删除第一个,因为您没有保留指向它的指针。
  6. 与 5 完全相同。
  7. 不编译。 Foo foo5 是声明,不是表达式;函数(和构造函数)参数必须是表达式。
  8. 创建一个临时对象,并通过复制来初始化一个动态对象。只有动态对象被泄露;临时在完整表达式结束时自动销毁。请注意,您可以只使用 Foo() 而不是等效的 Foo::Foo()(或者实际上是 Foo::Foo::Foo::Foo::Foo())来创建临时文件

我什么时候使用它们?

  1. 不要,除非您喜欢对代码进行不必要的修饰。
  2. 当您想要创建一个超出当前范围的对象时。用完记得删除,学习如何使用智能指针更方便地控制生命周期。
  3. 当您想要一个仅存在于当前范围内的对象时。
  4. 不要,除非你觉得 3 看起来很无聊,还有什么要添加一些不必要的装饰。
  5. 不要,因为它会泄漏内存而没有恢复的机会。
  6. 不要,因为它会泄漏内存而没有恢复的机会。
  7. 不要,因为它不会编译
  8. 当您想从临时 Foo 创建动态 Bar 时。

【讨论】:

  • 1. Allocates some dynamic memory from the free store, and creates an object in that memory using its default constructor. You never delete it, so the memory is leaked. 为什么我从不删除它?我可以打电话给delete foo1
  • @Kolyunya:是的,你可以,而且应该。但是你没有在你的示例代码中这样做,我认为这值得指出。
【解决方案3】:

第 1、2、3、4 行将调用默认构造函数。它们本质上是不同的,因为 1,2 是动态创建的对象,而 3,4 是静态创建的对象。

在第 7 行,您在参数调用中创建了一个对象。所以这是一个错误。

第 5 行和第 6 行是内存泄漏的邀请。

【讨论】:

    猜你喜欢
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    • 2014-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多