【问题标题】:Why do I need to instantiate an object in C#, but not in C++ in order to access a class's functions? [closed]为什么我需要在 C# 中实例化一个对象,而不是在 C++ 中才能访问类的函数? [关闭]
【发布时间】:2016-07-21 19:55:03
【问题描述】:

我最近开始使用 C# 进行 Unity(游戏引擎)开发。我注意到这与 C++ 不同; C# 要求我在使用其成员函数或变量之前在堆上实例化一个对象。与 C++ 一样,我可以声明一个对象并从声明名称调用任何函数。

C++ 示例:

#include <iostream>
using namespace std;
class SampleClass 

{
   void PrintFunc()
   {
      cout<<"Hello World"<<endl;
   }
 }

int main()
{

   SampleClass objectC; //Object declaration
   objectC.PrintFunc(); //Use of function without instantiation

   //The above code will print'Hello World'
}

C# 示例:

 using System

 namespace ConsoleProject2
{
    class MainClass
   {

   class SampleClass
   {
        Void PrintFunc()
        {
          Console.WriteLine("Hello World");
        }
    }

    public static void Main (string[] args)
    {

        SampleClass objectC = new SampleClass();
        //Must instantiate before accessing member functions 
        objectC.PrintFunc(); //Prints out 'Hello World'

    }
}

}

在 Unity 的 Automatic Memory Management 网站上阅读时,我只能得出结论,由于它是自动垃圾收集,它可能需要您将新对象放在堆上,因为它会为您解除分配。 (可能是错误的假设,请纠正我)

为什么这两种语言在访问对象属性时会有所不同?由于没有实例化,C++ 中的对象是否被放置在堆栈上;如果是这样,为什么不将所有对象都放在堆栈上?

谢谢。

【问题讨论】:

  • 因为它们是不同的语言,仅此而已。
  • 您也在 c++ 代码中实例化一个对象。仅仅因为您没有明确调用new 并不意味着您没有创建对象。您正在使用 C++ 中的 自动存储持续时间 制作一个,并使用默认构造函数来执行此操作。
  • 用unity3d没关系。
  • 我认为主要问题是您将苹果(C++ 类)与橙子(C# 类)进行比较 - 更好的比较是 C++ 类与 C# 结构和 C++ 指向 C# 类的指针 - 每对的行为非常相似(我试图回答...)。
  • @jaggedSpire 这正是我的观点。自动存储持续时间将 C++ 对象放在堆栈上(因为在函数退出后将其删除);为什么我们不能在堆栈上放置一个 C# 对象?

标签: c# c++ memory memory-management


【解决方案1】:

网上有很多关于这个话题的错误信息,所以请认真阅读。

我注意到,与 C++ 不同,C# 要求我在使用其成员函数或变量之前在堆上实例化一个对象。

这是在 C# 中思考它的错误方式。不要将“新”视为“使存储在堆上的东西”。将“new”视为“调用初始化对象的构造函数的事物”。无论该对象是通过复制它(值类型)来传递还是通过自动解除对它的引用(引用类型)来访问,都不会改变每个对象都需要以确保它已正确初始化,无论它是长期存储还是短期存储。

由于没有实例化,C++中的对象是否被放置在堆栈中

有一个实例化,您只是看不到它,因为它没有在代码中显示。为您调用了默认构造函数。

如果是这样,为什么不将所有对象都放在堆栈上?

停止思考“堆栈”和“堆”,开始思考“短生命周期变量”和“长生命周期变量”。为什么我们不将所有对象都放在短期变量池中? 因为有些对象的寿命很长,这就是原因。

放松,让垃圾收集器完成它的工作。它做得很好!

【讨论】:

    【解决方案2】:

    在 CLR 中,对象默认创建在堆上。

    https://msdn.microsoft.com/en-us/library/f144e03t(v=vs.110).aspx

    有很多方法可以在堆栈上创建对象,但通常一切都是在堆上创建的。

    在 C++ 中,使用 new 在堆上创建对象,而 Object o; 在堆栈上创建对象。

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa366533(v=vs.85).aspx

    【讨论】:

      【解决方案3】:

      C++ 和 C# 在值类型的行为上没有区别*(从 C# 的角度来看,C++ 类是什么)。

      以下 C# 代码编译并运行良好,代码与 C++ 版本相同:

      public static void Main (string[] args)
      {
        SampleClass objectC; // variable declaration, initialized with default of type
        objectC.PrintFunc(); //Use of function of object just initialized
      }
      
      
      struct SampleClass // note: "struct" in C# matches C++ "class"/"struct"
      {
           public void PrintFunc()
          {
            Console.WriteLine("Hello World");
          }
      }
      

      反之亦然:C++ 中的指针大致相当于 C# 中的类,并且以下 C++ 代码不起作用:

      int main()
      {
         SampleClass* objectC; // "SampleClass*" in C++ is equivalent 
                               // of variable of class type in C# 
         objectC->PrintFunc(); //try to use of function without instantiation
      
         //The above code will NRE
      }
      

      * 语言和平台确实有很大的不同,但是比较 C# 类和 C++ 类是试图将一种语言的概念理解应用到另一种语言的错误方法。

      heap vs. stack的详细解释是实实在在的answer by Eric Lippert...

      【讨论】:

        【解决方案4】:

        在 C++ 中,编写 SomeClass objectName; 会调用默认构造函数来初始化对象。一般来说,C++ 中没有类类型的未初始化值。

        【讨论】:

        • “C++ 中没有未初始化的值”是吧?
        • @user4759923 非类、非数组类型的默认初始化导致"no initialization to be performed"。 (和数组默认初始化它们的元素)结果是不确定值
        • 我澄清了我的答案
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-03-08
        • 1970-01-01
        • 2011-01-09
        • 1970-01-01
        • 1970-01-01
        • 2015-05-30
        • 1970-01-01
        相关资源
        最近更新 更多