c ++中的实例化

时间:2011-03-21 15:14:51

标签: c++ oop object

首先,我想通知你,我一直在搜索关于我的下一个问题的答案,但我是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;
}

Person.h

#ifndef PERSON_H
#define PERSON_H

#include <string>

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

#endif // PERSON_H

player.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();

进行实例化

我应该使用哪一个?

另一个我渴望的问题是,我是否在头文件或类文件中定义类成员?

目前我收到以下错误:

  

'人'未在范围内宣布并且预期';'在人之前

我不是故意要求你解决我的错误,我会在收到问题的答案后对此进行管理。

8 个答案:

答案 0 :(得分:4)

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

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

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

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

对于班级成员:

  • 他们 在头文件中声明;如果您没有声明它们并尝试使用它们,则会出现编译器错误。
  • 它们可以选择在头文件中定义;如果没有,您可以在.cpp文件中定义它们;如果你没有在任何地方定义它们并试图使用它们,你将得到一个链接器错误。

一般来说,定义应该转到.cpp文件,但是如果你在标题中定义了非常简短的方法就没问题。

<强>附录

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

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

答案 1 :(得分:2)

  1. Person person将在堆栈上构造一个对象。 Person *person = new Person将在内存中构建它在免费商店(堆;注意*,因为你需要一个指针)。这与C#不同,在C#中,您可以在structclass之间进行选择,以获得堆栈或堆分配。在C ++中,这些关键字具有不同的含义。如果您选择在堆上进行分配,则必须稍后delete手动对象。
  2. 实现不受标题更改的小型,性能关键型方法。将其他所有内容放在实现文件中。
  3. 不要在头文件的顶层放置using指令。)

答案 2 :(得分:2)

相当于你的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

答案 3 :(得分:1)

main.cpp 的开头,您还必须#include "Person.h"

答案 4 :(得分:1)

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

答案 5 :(得分:1)

如果您来自C#,这种解释可能会有所帮助:

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

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

詹姆斯在评论中指出,获得一本好的C ++书是最好的选择。

答案 6 :(得分:1)

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

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

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)
  {}
};

答案 7 :(得分:1)

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

无论如何,如果您定义了值语义,那么(差不多 never)动态分配实例。您将它们定义为本地 变量,根据需要复制它们,让编译器接受 照顾其余的。您还要确保复制,分配和 析构函数做你想要的 - 在现代C ++中,这通常是 这种情况,因为您的应用程序级别对象将基于 具有复制构造函数,赋值和的低级对象 做正确的事情的破坏,但这曾经不是 这种情况,今天并非总是如此。如果你想 实体语义,你必须决定什么是生命周期 实体应该是。 (我会像其他人一样说 语言,但许多Java和C#程序员忘记了这一点。和 经常侥幸逃脱。你永远不会逃脱它 C ++。)实体对象通常使用new创建,必须使用new 在他们的生命结束时被毁坏。

禁止复制和分配实体也是一种好习惯 C ++中的对象(除了可能提供克隆函数)。

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

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