【问题标题】:instantiation in c++C++中的实例化
【发布时间】:2011-07-19 18:36:27
【问题描述】:

首先,我想通知您,我已经明确搜索了有关我以下问题的答案,但我是 C++ 的新手。

我来自 C# 和 Java 的奢华生活,现在正在尝试学习一两点关于 c++ 的知识

问题是关于实例化的。

我使用 code::block 作为我选择的 IDE。

目前我只是在玩 C# 中的内容(我实际上非常熟悉并编写了几个应用程序)是

2 类

包含 main 和 Person 的类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;


using Models.Person;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
           Person person = new Person();
           Console.WriteLine(person.getName());
        }
    }
}

还有人物类:

namespace ConsoleApplication1
{
   public class Person{
       private string name = "Bob";

       public string getName(){
           return name;
       }
   }
}

(不要介意错误或正确的书面语法,它只是为了模拟我想要实现的目标)

我想在 C++ 中实现同样的目标

我查了一下,在一定程度上了解了标题,并掌握了一些语法。这就是我现在所拥有的。

main.cpp

#include <iostream>
using namespace std;

int main()
{
   Person person;
   cout << person->getName() << endl;
}

人.h

#ifndef PERSON_H
#define PERSON_H

#include <string>

class Person
{
    public:
        Person();
        virtual ~Person();
        std::string getName();
    protected:
    private:
};

#endif // PERSON_H

播放器.cpp

#include "Person.h"
#include <string>

using std::string;

Person::Person()
{
    //ctor
}

Person::~Person()
{
}

string Person::getName()
{
    return name;
}

考虑到上面的代码,我有多个问题。

我从来没有找到一个好的资源来告诉我是否应该使用Person person;Person person = new Person(); 进行实例化

这两个中的哪一个是我应该使用的?

另一个我很想问的问题是,我是在头文件还是在类文件中定义类成员?

目前我收到以下错误:

'person' 未在范围内声明,应为 ';'在人之前

我并不是一定要你解决我的错误,我会在收到我的问题的答案后解决这个问题。

【问题讨论】:

  • “我刚从 C# 和 Java 的奢华生活中走出来,现在想学习一两点关于 c++ 的知识”确保你有 a good introductory C++ book C++与 Java 或 C# 几乎没有共同之处。
  • 在阅读 [那本很好的 C++ 入门书籍] 后,还可以考虑仔细阅读 C++ FAQ,因为它有很多有用的信息。
  • 感谢您提供的链接 ^^ 我将在 C++ 书籍上明确遵循您的建议。它是一种非常有趣的语言。

标签: c++ oop object


【解决方案1】:

正如 larsmans 所说,Person personPerson *person = new Person() 导致新的 Person 实例分别在堆栈/堆中分配。

这对您意味着什么(这是“我应该使用哪个?”问题的答案)是在第一种情况下,对象的内存是自动管理的(这是个好消息)。坏消息是对象的生命周期也是自动管理的,你无法控制它。只要person 变量超出范围,对象就会被销毁。期间。

在第二种情况下 (new),对象的生命周期由您管理(在您执行 delete person 之前它一直存在)。这里的坏消息是 memory 也由您管理:如果您不执行delete person,分配给该对象的内存将会泄漏。如果您在范围内的任何地方都不再引用person,这不会有任何区别。

因此,如果生命周期对您来说足够长,请不要使用指针。否则,您将不得不这样做。

对于班级成员:

  • 它们必须在头文件中声明;如果你不声明它们并尝试使用它们,你会得到一个编译器错误。
  • 可以选择在头文件中定义;如果没有,您可以在 .cpp 文件中定义它们;如果您没有在任何地方定义它们并尝试使用它们,您将收到 linker 错误。

一般定义应该放在.cpp文件中,但是如果你在头文件中定义非常短的方法也没关系。

附录

当然,我在这个简短的回答中没有涉及到很多细节。以下是您可能想要研究的一些重要内容:

  • 使用new/delete管理内存,除了内存泄漏,还会产生很多其他问题; 悬空指针(指向已释放的内存,因此不能再使用 - 这本质上是“反向”错误而不是内存泄漏)可能在列表中排名第二。李>
  • 使用某种类型的智能指针将有助于实现“C# 语义”:每当指向某个内存的最后一个智能指针超出范围时,内存将在现场自动释放 (如果它指向一个对象,此时析构函数将运行;这称为确定性销毁,C# 没有它,它必须尝试用IDisposable 模拟它) .您可以在 C++0x 和 Boost 中使用非常好的和成熟的智能指针。
  • 在 C++ 中,所有类型都像 C# 值类型一样工作。如果a 占用了 2MB 内存,而您使用了b = a,那么您只需让编译器使用a 的副本填充一个全新的 2MB 内存(并且可能需要做很多额外的工作来实现这一点)。如果这不是您的意图,您需要将指针或引用存储到a

【讨论】:

  • 添加到新/删除。使用智能指针来管理你的对象生命周期是很聪明的。有多种选择。其中一些是 auto_ptr、shared_ptr、unique_ptr、scoped_ptr、weak_ptr。
  • 这是一个非常有趣且易于理解的小教程。非常感谢。非常清晰!
  • @Joey:谢谢你的好话。我添加了一个新部分,其中包含一些有用的提示,供从 C# 开始使用 C++ 的人使用。
【解决方案2】:
  1. Person person 将在堆栈上构造一个对象。 Person *person = new Person 将在内存中的空闲存储(堆;注意* 因为你需要一个指针)中构造它。这与 C# 不同,您可以在 structclass 之间进行选择以获取堆栈或堆分配。在 C++ 中,这些关键字具有不同的含义。如果您选择在堆上分配,那么您必须稍后手动delete 对象。
  2. 实施小型、性能关键的方法,这些方法不会在标头中更改。将其他所有内容放在实现文件中。

不要在头文件的顶层放置using指令。)

【讨论】:

  • 它是new Person,如果你默认构造一个Person,则不带括号。
  • @filmor:并非如此。在这种特殊情况下,两种语法完全相同(因为该类具有默认构造函数)。还是我错过了什么?
  • 从不在头文件的顶层使用 using?为什么?感谢您留下答案 ^^ 您的评论与 Nawaz 的回答相得益彰。
  • @Joey:因为它直接或间接地污染了包括该标头在内的任何模块的命名空间,随着程序规模和复杂性的增长,这可能会导致意外。 #include 只是文本替换:标题的全部内容都填写在 #include 所在的位置。
  • 啊,这就解释了。我从这个单线程中学到了很多东西。它确实是一门美妙的语言,它可以让你,也可以很容易地打破你。哈哈。这也是我学到的。我真的很喜欢学习它。谢谢:)
【解决方案3】:

相当于你的 C# 代码是这样的:

#include <iostream>
#include <string>

class Person
{
   std::string name;
   public:
     Person() : name("Bob"){}
     std::string getName() { return name; }   
};

int main()
{
   //automatic variable; doesn't need new!
   Person person;
   std::cout << person.getName() << std::endl;

   //pointer ; need to use new
   Person *pPerson = new Person(); //it allocates memory!
   std::cout << pPerson->getName() << std::endl;
   delete pPerson; //it deallocates the memory!
}

输出:

Bob
Bob

查看在线演示:http://ideone.com/cM0uU

【讨论】:

  • 谢谢。更清楚了,这是我无法要求的。欣赏它,尤其是示例解释,结合其他人的cmets非常有帮助。再次感谢。
  • 我添加了一个删除来清理内存。 Joey,重要的是要始终记住 C++ 没有垃圾收集,你必须自己清理。 :-)
  • @Daniel 或@Nawaz,当您制作指针时,是否常见以 p 为前缀?不过,这将是合乎逻辑的,只是好奇。 @Daniel T:呵呵,没有垃圾收集器会习惯一些,但经过一些试验和错误后,会习惯它,不管是否经历了艰难的过程。 :)
  • @Joey:人们通常会写作,但这不是必需的。这只是一种编码风格。
  • @Joey:我通常不使用“p”前缀。至于缺少的垃圾收集器,大多数程序员都有一套工具可以使清理工作至少是半自动的(AKA 智能指针,其中一些正在进入 C++ 标准。)
【解决方案4】:

关于 Person 的主要区别是你是否想要价值 语义或引用语义---对于实体对象,引用 语义是必要的(因为它们保留了身份),但对于 大多数其他人,价值语义是可取的。在你的例子中, Person 可以很容易地使用值语义,但是在 一个更现实的案例,这将取决于班级的角色 在应用程序中。

不管怎样,如果你定义了值语义,你就(几乎 从不)动态分配实例。您将它们定义为本地 变量,根据需要复制它们,然后让编译器取 照顾其余的。您还要确保复制、分配和 析构函数做你想做的——在现代 C++ 中,这通常是 这种情况,因为您的应用程序级对象将基于 具有复制构造函数、赋值和 做正确的事情的破坏,但这过去不是 情况,今天并非总是如此。如果你想 实体语义,你必须决定 实体应该是。 (我会说就像你在其他 语言,但许多 Java 和 C# 程序员忘记了这一点。和 经常侥幸逃脱。你永远不会逃脱它 C++。)实体对象通常使用 new 创建,并且必须 当他们的生命结束时被摧毁。

禁止复制和转让实体也是一种很好的做法 C++ 中的对象(可能提供克隆功能除外)。

关于第二点:完整的类定义必须 在一个地方;你不能重新打开定义一次 你已经用最后一个花括号关闭了它。这意味着 成员函数声明(但不是定义)和 成员数据必须存在于类定义中,在 头文件。最好尽量少放 但是,头文件和函数的定义( 实现)通常属于源文件。

(所有这些规则都有例外,但它们很好 起点。)

【讨论】:

    【解决方案5】:

    ma​​in.cpp的开头你还必须#include "Person.h"

    【讨论】:

      【解决方案6】:

      在 java 中,一切都是引用类型,因此必须使用 new 实例化,它创建一个值类型并返回对它的引用。在c++中,基本类型是值类型,类似于java的引用类型看起来像Person* person;当你进入 c++ 并从基础开始时,你真的应该放弃你从 java 中所知道的一切,从高级编程到低级编程真的很混乱

      【讨论】:

        【解决方案7】:

        如果您来自 C#,此说明可能会有所帮助:

        在 C++ 中,类型的声明/定义并没有说明它是“值类型”还是“引用类型”。 “struct”和“class”之间的唯一区别是成员在“class”中默认是私有的。这取决于你如何使用它。

        当您声明Person 时,您将其创建为“值类型”。 当您声明Person* 时,您正在创建一个指向Person 的指针(C# 中的引用类型),该指针通常使用new 在堆上分配。 C++ 中的引用(即Person&amp;)类似于C# 中的ref Person

        正如 James 在他的评论中指出的那样,获得一本好的 C++ 书籍是您最好的选择。

        【讨论】:

        • 我一定会得到那本书。 C++ 社区似乎也很有帮助,他们只会激励我更多地在 C++ 中变得更好,并且以后能够自己回答一些问题! :) 在旁注中,我喜欢你如何解释 C# 等价物。谢谢。
        【解决方案8】:

        您遇到的错误来自不使用#include "Player.h"(假设这是您命名的包含class Person 声明的头文件,因为这是您的#define PLAYER_H 建议的内容)。之后,它会抱怨,因为您使用的是person-&gt;getName() 而不是person.getName()-&gt; 与指针一起使用,您可能应该对此进行更多阅读。

        至于定义类成员,如果我理解正确的术语,你应该在你的头文件中声明它们。然后它们在类文件的构造函数中定义,通常是隐式的。

        class MyClass {
          int myVar;  // Declare the variable
        public:
          MyClass(int inVar);  // Declare the constructor function
        };
        

        然后在类文件中:

        MyClass::MyClass(int inVar)  // Define the constructor function
        : myVar(inVar)     // Define the variable
        {
        }
        

        当然,你可以在头文件中两者都做,有时这样做是合适的。

        class MyClass {
          int myVar;  // Declare the variable
        public:
          MyClass(int inVar) // Declare and define the constructor function
          : myVar(inVar)
          {}
        };
        

        【讨论】:

        • 啊抱歉,我也忘记将它们更改为 Person。我正在更改我的个人示例,似乎我有点草率,这样做的原因是我想使用与我在 C# 中相同的示例,但是后来用 C++ 编写,我现在已经更改了它们,实际上得到了它工作。感谢您的通知!我也会在我的帖子中更改它。一个愚蠢的初学者错误我想呵呵。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2023-03-19
        • 2014-05-15
        • 2019-04-06
        • 2016-06-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多