инстанцирование в с ++ - PullRequest
5 голосов
/ 21 марта 2011

Прежде всего, я хотел бы уведомить вас, я определенно искал ответы на мой следующий вопрос, но я полный новичок в 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 ]

4 голосов
/ 21 марта 2011

Как сказали larsmans, Person person и Person *person = new Person() приводят к тому, что новый экземпляр Person размещается в стеке / куче соответственно.

Что это значит для вас (и это ответ на вопрос «что мне следует использовать?») Заключается в том, что в первом случае память для объекта управляется автоматически (это хорошая новость). Плохая новость заключается в том, что время жизни объекта также управляется автоматически, и вы не можете его контролировать. Как только переменная person выходит из области видимости, объект уничтожается. Период.

Во втором случае (new) вы управляете временем жизни объекта (оно будет существовать до тех пор, пока вы не выполните delete person). Плохая новость в том, что память также управляется вами: если вы никогда не сделаете delete person, память, выделенная этому объекту, будет утечка. Это не будет иметь никакого значения, если вы больше не будете ссылаться на person в области видимости.

Так что, если время жизни достаточно для вас, не используйте указатель. В противном случае вам придется.

Для учеников:

  • Они имеют , чтобы быть объявленными в заголовочном файле; если вы не объявите их и не попробуете их использовать, вы получите ошибку compiler .
  • При желании они могут быть определены в заголовочном файле; если нет, вы можете определить их в файле .cpp; если вы нигде не определите их и не попробуете их использовать, вы получите ошибку linker .

Обычно определения должны идти в файл .cpp, но это нормально, если вы определяете действительно короткие методы в заголовке.

Добавление

Конечно, есть много деталей, которые я не затронул в этом коротком ответе. Вот несколько важных, на которые вы, возможно, захотите взглянуть:

  • Использование new / delete для управления памятью также может породить множество других проблем, кроме утечек памяти; висячие указатели (которые указывают на память, которая была освобождена и поэтому больше не может использоваться - это, по сути, «обратная» ошибка, чем утечка памяти), вероятно, №2 в списке.
  • Использование какого-либо умного указателя поможет в достижении "семантики C #": всякий раз, когда последний умный указатель на какую-то память выходит из области видимости, память автоматически освобождается на месте (если он указывает на объект, деструктор будет запущен в это время; это называется детерминированное уничтожение , у C # его нет, и он должен попытаться эмулировать его с помощью IDisposable). Есть очень хорошие и зрелые умные указатели, которые вы можете использовать в C ++ 0x и Boost.
  • В C ++ все типы работают как типы значений C #. Если a занимает 2 МБ памяти, а вы делаете b = a, то вы только что заставили компилятор заполнить совершенно новые 2 МБ памяти копией a (и, вероятно, проделали большую работу для достижения этой цели). Если это не ваше намерение, вам нужно сохранить указатель или ссылку на a.
2 голосов
/ 21 марта 2011

Эквивалент вашего кода 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

2 голосов
/ 21 марта 2011
  1. Person person создаст объект в стеке.Person *person = new Person создаст его в памяти в бесплатном хранилище (куча; обратите внимание на *, потому что вам нужен указатель).Это отличается от C #, где вы можете выбрать между struct и class, чтобы получить выделение стека или кучи.В C ++ эти ключевые слова имеют другое значение.Если вы решите выделить в куче, вы должны позже delete объект вручную.
  2. Реализация небольших, критичных к производительности методов, которые не могут быть изменены в заголовке.Поместите все остальное в файл реализации.

( Пожалуйста, не помещайте директиву using на верхнем уровне в заголовочном файле.)

1 голос
/ 21 марта 2011

Основное различие, касающееся личности, заключается в том, хотите ли вы ценить семантика или ссылочная семантика --- для объектов сущности, ссылка семантика необходима (так как они сохраняют идентичность), но для большинство других, семантика значения предпочтительнее. В вашем примере Человека легко можно заставить работать с семантикой значения, но в более реалистичный случай, это будет зависеть от роли класса в приложении.

В любом случае, если вы определяете семантику значений, вы делаете , а не (почти никогда) распределять экземпляры динамически. Вы определяете их как местные переменных, копируя их по мере необходимости, и пусть компилятор заботиться об остальном. Вы также убедитесь, что копия, назначение и деструктор делает то, что вы хотите --- в современном C ++, это обычно случай, поскольку ваши объекты уровня приложения будут основаны на объекты нижнего уровня с конструкторами копирования, назначением и разрушения, которые делают правильные вещи, но это не было дело, и это не всегда так сегодня. Если ты хочешь семантика сущности, вы должны решить, какова продолжительность жизни сущность должна быть. (Я бы сказал, как и в других языки, но многие программисты на Java и C # забывают об этом. А также часто сходит с рук. Вам не сойдет с рук, когда-либо, в C ++.) Объекты Entity обычно создаются с использованием new и должны быть уничтоженным, когда закончится их жизнь.

Это также хорошая практика, чтобы запретить копирование и присвоение объекта объекты (кроме, возможно, для обеспечения функции клона) в C ++.

По второму пункту: полное определение класса должно быть в одном месте; Вы не можете открыть определение один раз вы закрыли его с помощью последней фигурной скобки. Это означает, что объявления функций-членов (но не определения) и данные члена должны присутствовать в определении класса, в заголовочный файл Лучше всего положить как можно меньше в Однако, заголовочный файл и определения функций ( реализация) обычно принадлежит исходному файлу.

(Есть исключения из всех этих правил, но они хорошие отправная точка.)

1 голос
/ 21 марта 2011

Ошибки, которые вы получаете, возникают из-за того, что вы не используете #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)
  {}
};
1 голос
/ 21 марта 2011

Если вы пришли из C #, это объяснение может быть полезным:

В C ++ объявление / определение типа не говорит, является ли это «типом значения» или «ссылочным типом»,Единственная разница между «struct» и «class» заключается в том, что члены по умолчанию являются частными в «class».Это определяет то, как вы его используете.

Когда вы объявляете Person, вы создаете его как «тип значения».Когда вы объявляете Person*, вы создаете указатель (ссылочный тип в C #) на Person, который обычно выделяется в куче с помощью new.Ссылки (т. Е. Person&) в C ++ похожи на ref Person в C #.

Как отмечает Джеймс в своем комментарии, лучше всего получить хорошую книгу по C ++.

1 голос
/ 21 марта 2011

В Java все является ссылочным типом, и его необходимо создавать с использованием new, который создает тип значения и возвращает ссылку на него. В c ++ базовый тип является типом значения, а ссылочный тип, похожий на Java, выглядит как Person * person; Вы должны действительно отбросить все, что вы знаете из java, когда переходите на c ++, и начинать с основ, действительно может быть очень запутанно переходить от программирования к высокому уровню к низкому уровню

1 голос
/ 21 марта 2011

В начале main.cpp вы также должны #include "Person.h".

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...