首先,我想通知你,我一直在搜索关于我的下一个问题的答案,但我是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();
我应该使用哪一个?
另一个我渴望的问题是,我是否在头文件或类文件中定义类成员?
目前我收到以下错误:
'人'未在范围内宣布并且预期';'在人之前
我不是故意要求你解决我的错误,我会在收到问题的答案后对此进行管理。
答案 0 :(得分:4)
正如larsmans所说,Person person
和Person *person = new Person()
导致新的Person
实例分别在堆栈/堆中分配。
这对你意味着什么(这是“我应该使用哪个?”问题的答案)是在第一种情况下,对象的内存是自动管理的(这是好消息)。坏消息是对象的生命周期也会自动管理,而您无法对其进行任何控制。只要person
变量超出范围,对象就会被销毁。周期。
在第二种情况下(new
),对象的生命周期由您管理(它将一直存在,直到您执行delete person
)。这里的坏消息是内存也由你管理:如果你不做delete person
,分配给该对象的内存将泄漏。如果你不再在范围内的任何地方引用person
,那就没有任何区别了。
因此,如果生命周期足够长,请不要使用指针。否则,你将不得不这样做。
对于班级成员:
一般来说,定义应该转到.cpp
文件,但是如果你在标题中定义了非常简短的方法就没问题。
<强>附录强>
当然,在这个简短的回答中我没有提到很多细节。以下是您可能想要了解的一些重要内容:
new
/ delete
管理内存除了内存泄漏外,还会产生许多其他问题; 悬空指针(指向已释放的内存,因此不能再使用 - 这实际上是“反向”错误,而不是内存泄漏)可能是列表中的#2。IDisposable
占用2MB内存并且a
,那么您只需要编译器使用b = a
的副本填充一个全新的2MB内存(并且可能需要做很多额外的工作)实现这一点)。如果这不是您的意图,则需要将指针或引用存储到a
。答案 1 :(得分:2)
Person person
将在堆栈上构造一个对象。 Person *person = new Person
将在内存中构建它在免费商店(堆;注意*
,因为你需要一个指针)。这与C#不同,在C#中,您可以在struct
和class
之间进行选择,以获得堆栈或堆分配。在C ++中,这些关键字具有不同的含义。如果您选择在堆上进行分配,则必须稍后delete
手动对象。(请不要在头文件的顶层放置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 ++中的对象(除了可能提供克隆函数)。
关于第二点:完整的类定义必须 在一个地方;你不能重新打开一次这个定义 你用最后一个大括号把它关了。这意味着 成员函数声明(但不是定义)和 成员数据必须出现在类定义中 头文件。最好尽可能少地放入 但是,头文件和函数的定义( 实现)通常属于源文件。
(所有这些规则都有例外,但它们很好 起点。)