【问题标题】:C# objects and C++ objects, the differenceC# 对象和 C++ 对象的区别
【发布时间】:2010-12-17 02:12:39
【问题描述】:

在 C# 中创建对象实例时

Myclass mc = new Myclass();

这个mc 现在是对在内存中创建的Myclass 对象的引用。这就像一个指向那个记忆的“指针”。

它是否与在(托管或非托管)C++ 中执行此操作相同或可比:

MyCppClass *mcCppClass = new MyCppClass();

因为这实际上创建了一个指向类的对象实例的指针。

我只是想找出到底有什么区别?

【问题讨论】:

  • 因此 C++ 指针可以指向内存中已经存在的对象,也可以在内存中创建新对象。虽然你也可以在 C# 中做到这一点......你什么时候会在 C++ 中创建对对象的引用,然后你会创建指向该对象的指针?
  • 根据我的经验,通常在将参数传递给函数时使用引用。如果您有一个对象并按值传递它,则会复制该对象,这可能会很昂贵,具体取决于复制构造函数和析构函数的作用。但是,如果将其作为引用传递,则可以避免复制构造函数和析构函数调用的开销。它通常更有效。
  • 抱歉听起来很傻,但是 C# 引用可以引用任何相同类型的对象。因为可以在 C# 中更改对象引用。 C++ 中的引用总是指向它所引用的任何东西的同一个实例。对吗?
  • @Tony:对。 C++ 引用是对象的不同名称(松散地使用术语),您不能更改哪个对象。 C++ 具有执行 C# 引用将执行的任何操作(包括自动销毁)但不在同一个包中的构造。

标签: c# c++ pointers


【解决方案1】:

似乎没有人提到的一个重要区别是:

Myclass mc = new Myclass();

在 C# 中,这是唯一创建新对象的正确方法。当您需要一个对象时,这就是您创建它的方式。

MyCppClass *mcCppClass = new MyCppClass();

在 C++ 中,这就是您可以创建对象的方式,以及您偶尔必须创建对象的方式。在 C++ 中使用这种方法的问题在于:

  • 与托管语言相比,new 在 C/C++ 中非常慢。如果用于分配您需要的每个对象,那会很痛苦。
  • 对象没有固定的生命周期。它是在堆上分配的,并且在您调用delete 之前它不会被销毁。如果您忘记这样做,它永远不会被破坏。如果你两次调用delete,你的程序就会崩溃。

在 C++ 中,您有两种创建对象的方法: 您在上面使用的那个:

// 1
MyCppClass *myobject = new MyCppClass();
delete myobject;

但修改为也包含 delete 调用,因为没有它,你会泄漏内存。 每当你使用 new 时,你也必须迟早调用 @987654329 @。一般来说,一个没有另一个是错误的。

第二种更常见的方法:

// 2
MyCppClass myobject;

第二个在某些方面更类似于您的 C# 示例。它的生命周期由系统自动管理(尽管它的管理方式不同。在 C++ 中,它会一直持续到超出范围,而在 C# 中,它会一直持续到没有人引用它并且它会被垃圾回收 - 但在这两种情况下,您不必做任何事情来确保它被销毁)。出于同样的原因,这也是创建对象实例的正确方法。

新 C++ 程序员最常犯的错误之一是使用new 分配每个对象,存储指向它们的指针,然后尝试 记住删除它们。一个更简单、更健壮、更有效的解决方案是避免new,并尽可能避免使用指针。有时,您需要一个对象,其生命周期不限于声明范围,(并且复制对象不是在该范围之外使用它的选项)。然后使用new,并且很可能将生成的指针包装在某种类型的智能指针中。

【讨论】:

  • 对于新的 C++ 程序员来说,一个简单的技巧是使用智能指针而不是原始指针。只需将每个指针变成std::tr1::shared_ptr<> 就可以解决很多问题。这不是一直都做的正确的事情,但它会运作良好并且是一个容易记住的规则。
  • 我宁愿提到 C# 指针更像是 C++ 中的 boost::shared_ptr。这将赋予它在两种语言中相同的使用语义。认为两种语言中的对象相同(语义上它们看起来相同)是不公平的,但是在 C# 对象上发生了很多额外的编译器工作,而在 C++ 指针上没有完成。
  • 我不同意自定义对象的堆栈分配比堆分配更常见。此外,您跳过了引用类型和值类型之间的区别。 'a = b' 在 C# 中的含义非常不同,具体取决于 a 和 b 是引用类型还是值类型。
  • 在第一部分,你是(或应该是)错了。在知道自己在做什么的 C++ 程序员中,堆分配很少见。当它发生时,它通常被包装在一个堆栈分配的 RAII 对象中——就像std::vector 所做的那样。没错,我跳过了 .NET 的值类型。原因是它们大部分与这个答案无关。它们并不完全符合我所说的关于生命周期持续到对象被 GC'ed 的说法,但 a = b 的语义与这个答案无关,所以我不明白为什么我应该提到这一点。跨度>
  • a = b 的语义是相关的,因为 Tony 声明“因为这实际上创建了一个指向类的对象实例的指针”。这意味着他还不了解引用类型和值类型之间的区别。
【解决方案2】:

在 C++ 中,您负责删除该内存,而在 C# 中则不是。这可能是您要记住的最大区别。

就相似之处而言,它们都是堆分配的对象。

Here 是一篇关于 C# 中堆与堆栈的好文章,您可能会发现它很有用。

【讨论】:

    【解决方案3】:

    它们相似,但 C# 版本有一些重要的注意事项:

    • 您可以使用 new Blah() 创建值对象和引用对象。值对象的行为与引用对象不同:分配它们会复制数据,而不是引用。

    • C# 引用对象被垃圾回收

    【讨论】:

      【解决方案4】:

      在这个例子中,我认为 C# 版本更类似于 reference

      MyCppClass *mcCppClass = new McCppClass();
      MyCppClass &reference = *mcCppClass;
      

      在 C++ 中,您不必担心 reference 指向 null,因为它是。它就在那里,所以你可以使用它。但是,在 C# 中,对象引用 可以为空。

      另外,正如@Kyle Walsh 指出的那样,您有责任删除与 C++ 中的 mcCppClass 指针关联的内存。在 C# 中,您的对象将自动被垃圾回收。

      需要注意的一点是,C# 区分了类和结构。类是引用类型,而结构是值类型。在 C++ 中,类和结构仅在其默认成员可见性级别上有所不同(类默认具有私有成员可见性,而结构默认具有公共成员可见性)。如果从 C++ 迁移到 C#,这是需要注意的一个重要区别。详情请见here

      【讨论】:

      • 我同意与引用的相似性,正如你所说,引用在 C++ 中不能为空。但是,它们可以在 C# 中为 null ;-)
      • C# 引用被允许为null,而 C++ 引用则不允许。此外,C# 引用确保其目标的生命周期至少与对它的每个引用一样长,而 C++ 引用则没有。他们实际上几乎没有共同点。几乎唯一的共同点是它们可以在没有特殊的取消引用语法的情况下使用,因此使用点来访问成员。
      【解决方案5】:

      它可能被称为引用,但它作为指针处理(它可以是 NULL)。在 C++ 中,引用不能为空,它总是引用 same 实例。

      在 C++ 中,引用和指针之间有很大的区别。并且 C#(或 java 的)“引用”更接近于 C++ 指针而不是 C++ 引用。

      int a = 3;
      int b = 2;
      int & c = b; // c and b will alway refer to the same thing.
      c = a;    
      std::cout << b << std::endl; // shows 3
      
      int * pa = new int(3);
      int * pb = new int(2);
      int * pc = pb;
      pc = pb; // pc and pb are now refering to different things
      
      std::cout << *pb << std::endl;// shows 2
      

      在 C++ 中,您无需在免费存储中分配实例(« using new »)。您也可以在堆栈上声明它们。在后一种情况下,您不必担心删除它们。

      【讨论】:

        【解决方案6】:

        new 都为成员变量分配内存的意义上,它们是相等的。它们的不同之处在于 C++(在您的示例中)是指向内存中对象的指针,并且 C# 有一个引用(它不是指针,但也不是 C++ 引用,即它可以为空)。

        两种语言都保证new 的结果不为空,或者抛出错误(即C# 中的OutOfMemoryException)。

        当然,对象、类等的整体行为在 C++ 和 C# 中是完全不同的(垃圾收集、自动装箱行为、静态构造函数等)。

        编辑:在其他答案中尚未提及的一件事:C++ 中的任何new 都会调用完整的类层次结构的构造函数。 C# 仅是单继承,并且只会调用层次结构中的第一个构造函数或对象 ctor。在 C# 中,如果没有定义构造函数,new X() 等于 new object()

        【讨论】:

          猜你喜欢
          • 2014-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-09-25
          • 2021-10-22
          • 1970-01-01
          • 2011-07-19
          • 2011-10-07
          相关资源
          最近更新 更多