Как я должен писать классы? C ++ - PullRequest
1 голос
/ 18 февраля 2011

Привет .. Я действительно не понимаю их.Я прочитал учебник о классах в C ++, и у меня не хватает нескольких вещей: в каждом примере и учебнике, которые я видел, функции никогда не пишутся внутри класса!Например, зачем писать такой класс:

#include <iostream>

using namespace std;

class test
{
    private:
        int x, y;
    public:
        test (int, int);
        int tester () {return x + y; }
};

test::test (int a, int b)
{
    x = a;
    y = b;
}

int main()
{
    test atest (3, 2);
    test atest2 (2, 6);

    cout << "test1: " << atest.tester() << endl;
    cout << "test2: " << atest2.tester() << endl;

    return 0;
}

или вот так:

#include <iostream>

using namespace std;

class test
{
    private:
        int x, y;
    public:
        void set_values (int,int);
        int testfunc () {return x + y; }
};

void test::set_values (int a, int b)
{
    x = a;
    y = b;
}

int main()
{
    test tester;

    tester.set_values (3, 2);

    cout << "test1: " << tester.testfunc() << endl;

    return 0;
}

, а не просто так:

#include <iostream>

using namespace std;

class test
{
    public:
        int tester (int x, int y) { return x + y; }
};

int main()
{
    test atest;

    cout << atest.tester(3, 2) << endl;

    return 0;
}

Честно говоря, япросто не понимаю!

Зачем мне нужны приватные члены ??

Когда и как я должен использовать деструкторы?

Как я обычно пишу свои классы?

Я очень смущен здесь, и мне действительно нужен кто-то, чтобы прояснить для меня вещи ... спасибо

Ответы [ 10 ]

3 голосов
/ 18 февраля 2011

Как говорит Грег, вам действительно нужно читать книгу.

Как мне вообще писать свои классы?
Классы позволяют объединять данные и функции, которые на них действуют, в одну вещь.

Зачем мне нужны закрытые члены ??
Доступ к закрытым членам возможен только с помощью функций в вашем классе, это позволяет вам контролировать, как данные хранятся в классе, без того, чтобы пользователь класса мог делать то, что вы не делаете.Не ожидайте.

Когда и как я должен использовать деструкторы?
Когда у вас есть что-то, что нужно очистить, когда вам больше не нужен объект, файл закрыт или память освобождена.

2 голосов
/ 18 февраля 2011

Пример правдоподобно разделяет установку и получение значений, потому что между ними больше, чем вы видите в данной основной функции.Если этого не произошло, вы совершенно правы, что вам следует объединить их и даже исключить класс в пользу бесплатной функции.

Например, код может выглядеть примерно так:

void example(Test obj) {
  if (something) {
    process(obj.tester());
  }
}

int main() {
  int x, y;  // Imagine these are assigned to user input.
  Test obj (x, y);
  example(obj);  // Obj.tester may or may not be used.  If the x + y was not
  // separated, then you couldn't "maybe use" it.
  return 0;
}

Зачем мне нужны частные участники?

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

Когда и какя должен использовать деструкторы?

Когда вам нужна специальная логика уничтожения.Читайте о Правиле Трех .Напишите их, как если бы они были методом класса с именем «~» плюс имя класса, не принимая параметров и пропуская возвращаемый тип (даже void), так же, как и для ctors.

Как обычно писатьмои классы?

Вам не нужно определять методы вне класса.Фактически, для начала реализуйте все методы внутри класса, а затем перемещайте методы по мере необходимости.Это намного сложнее испортить, пока вы изучаете важные основы языка, и гораздо удобнее для типов классов, которые вы будете писать изначально.Используйте инициализаторы ctor, когда они осуществимы так же, как и присваивание в теле ctor.

struct Test {
  Test(int x, int y)  // Use the same names rather than inventing 'a' and 'b'.
  : _x (x), _y (y)
  {}

  int tester() const { return _x + _y; }
  // Move outside the class when needed, if at all -- and it won't be needed
  // for a function like this.
  // Because this doesn't modify anything, it's suitable to be const, which
  // means it can be called on a const Test object.

  int _x, _y;
  // Technically public, but with a "non-public name".  Mark private as you
  // wish, or as the design settles down.
};

Примечание. Я использовал "struct" для объявления этого класса вместо "class".Результат идентичен, за исключением того, что я пропускаю «public» в любых базовых классах (здесь их нет, но базы чаще общедоступны, чем нет), а доступность члена по умолчанию тоже «public»: это приводит к сокращению и чуть большемуочистить код.

1 голос
/ 18 февраля 2011

Должен ли я определять методы в теле класса? Зачем мне нужны частные члены?

Как сказал Фред, это часто легче делать при обучении, поиграть с кодом или даже в качестве профессионала, как первый набросок или другие обстоятельства. Стоит отметить, что определения тела класса автоматически становятся «встроенными», что означает, что компилятор вставляет код в вызывающую точку и может избежать накладных расходов на вызов функции.

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

  1. При написании клиентского кода мы можем лучше сосредоточиться на важных вещах.
  2. Если нам нужно исправить реализацию, у нас есть хороший шанс не нарушать клиентский код.

В конечном счете, все это сводится к попыткам решить проблему разработки программного обеспечения, заключающуюся в том, как разбить большие системы на компоненты, чтобы получить управляемую базу кода. C ++ позволяет вам определять интерфейсы, используя открытую часть тел классов и реализацию в виде частного раздела или файла .cpp. Это уменьшает общую связь в системе и, следовательно, ее общую сложность.

Когда и как мне использовать деструкторы?

Примером концепции инкапсуляции являются объекты «собственных» ресурсов. Любая вещь ресурса, которую создает объект, также ответственна за выпуск. Когда объект уничтожен, ему необходимо освободить оставшиеся ресурсы. Теперь часто для простых объектов вам не нужно ничего делать, ничего не делать. Основным случаем для нового программиста будет вызов 'delete' для объектов, созданных с использованием 'new'. Полезно избегать этого, используя умные указатели , такие как std :: auto_ptr <>.

Как мне вообще писать свои уроки?

Обязательно убедитесь, что вы понимаете, как разбить код на файл .cpp. Сделав это, для самообучения вам будет хорошо с кодом в теле класса. Вы можете обнаружить, что тело класса становится длинным и трудным для навигации. Это признак того, что сейчас нужно время, чтобы разделить его. Еще один хороший пример разделения - когда реализация «интересна». Предположим, у вас есть класс рисования, который реализован с использованием OpenGl. Помещение подробностей в файл .cpp означает, что остальная часть вашего кода не будет содержать заголовочные файлы OpenGl.

1 голос
/ 18 февраля 2011

Когда вы садитесь за руль автомобиля, у вас есть определенные ожидания относительно того, как управлять этим автомобилем.Поворот колеса влево должен повернуть машину влево.Нажатие на педаль газа должно привести к ускорению, а нажатие на педаль тормоза должно замедлить ее.Как водитель, вы имеете право делать эти предположения, потому что мир стандартизировал интерфейс , через который вы управляете автомобилем.

Итак, что если вы управляете электромобилем вместо автомобиля?двигатель двигателя внутреннего сгорания?Нужно ли менять колесо и / или педали?Конечно, нет!Глупо менять элементы управления просто , потому что некоторые технические компоненты автомобиля отличаются.Не должно иметь значения, работает ли автомобиль на газе, электричестве, воде, хомяках, или на чистой энергии воли;поворот колеса вправо должен привести машину в движение!

Когда дело доходит до проектирования объекта, публичные функции действуют как интерфейс для программиста.Программист может иметь общие предположения, что определенные вызовы функций будут давать определенные виды результатов.Продолжая аналогию с автомобилем, можно использовать хорошие общедоступные функции ускорения (), turnWheel (), toggleLights () и т. Д. Плохой общедоступной функцией будет fuelInjection ().Почему драйвер связан с работой этого конкретного компонента?Автомобиль должен обрабатывать эти детали!Хорошими частными членами были бы fuelInjection (), выхлоп () и т. Д.

Аналогия с автомобилем через некоторое время рушится, поэтому давайте рассмотрим более практичный пример.Допустим, вы делаете класс изображения.Как вы представляете взаимодействие с хорошим объектом изображения?Вот так?

Image i;
i.loadFromFile("myFace.jpg");

Или вот так?

Image i;
i.preparePixelBuffer();
memset(i.pixelBuffer, 0, i.pixelBufferSize);
FILE* fp = fopen("myFace.jpg", "r");
bool doneLoading = false;
while (!doneLoading)
...

Никогда не используйте объекты / классы "только потому, что".Подумайте о сфокусированном кратком поведении, которое вы хотите включить в класс.Это сделает вашу жизнь намного проще!

1 голос
/ 18 февраля 2011

Зачем мне нужны закрытые члены ??

Закрытые члены позволяют применять инварианты классов.Скажем, ваш класс представляет банковский счет, вы хотите, чтобы у вас была идея, что на вашем счету не может быть отрицательных денег.Класс не может гарантировать, что любой код может изменить баланс аккаунта.Сделайте баланс учетной записи частным, тогда класс сможет гарантировать, что свойство сохраняется.

Когда и как я должен использовать деструкторы?

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

Как мне вообще писать свои классы?

Общие руководящие указания по написанию классов будут следовать принципам SOLID.

1 голос
/ 18 февраля 2011

Частные члены скрывают внутренности класса от манипуляций извне.Это позволяет автору класса изменять внутренние детали реализации, не беспокоясь о нарушении другого кода, и позволяет классу оставаться в допустимом состоянии.(Рассмотрим треугольник с длинами участков в качестве открытых элементов данных: не было бы никакого способа помешать некоторому другому коду установить длины участков равными 2, 3 и 7.)

Деструктор, как правило, должен освобождать ресурсы, удерживаемыеобъект - такие вещи, как дескрипторы файлов, соединения с базой данных, блоки памяти в куче.Если у объекта нет таких ресурсов, обычно вам не нужно писать деструктор.Если это произойдет, вам, вероятно, также потребуется написать собственный конструктор копирования и оператор присваивания.(Можно использовать «умные указатели» для ссылки на блоки памяти, и у них есть свои собственные встроенные деструкторы.)

Вы должны написать свои классы, вычисляя, что объекты должны делать.Затем напишите объявления функций, которые позволяют вызывающим сторонам делать эти вещи.Это дает вам открытый интерфейс класса, поэтому эти функции должны быть public:.Затем напишите все, что вам нужно для реализации этих функций.Это почти наверняка будет включать данные, и, вероятно, будет включать другие функции, которые будут вызывать публичные функции.Эти вещи должны быть private:.

. В общем, определение класса входит в заголовочный файл, а заголовочный файл должен содержать как можно меньше.Заголовочный файл меньшего размера означает более быстрое общее время компиляции (поскольку заголовочный файл будет иметь размер #include d по крайней мере для одного файла кода) и уменьшает то, что другие люди, или вы, через шесть месяцев, должны прочитать, чтобы понять, что делает класс.Реализации идут в файле кода.

0 голосов
/ 18 февраля 2011

Многие люди говорят, что вам нужно разделить ваш класс на файл .h и файл .cpp. Это обычно делают программисты-хобби, потому что это помогает сделать огромные классы намного меньше, чтобы договариваться, когда вы оглядываетесь на них, чтобы увидеть, что они делают. Наличие всего кода, который делает этот класс фактически работающим в том же файле, что и все функции / члены-члены, которые вы можете использовать, затрудняет понимание того, как вы на самом деле можете «использовать» этот класс.

По сути, он позволяет вам просто посмотреть на заголовочный файл после его завершения и забыть, как на самом деле работает класс! По крайней мере, это цель. Когда вы занимаетесь профессиональным программированием или просто действительно большими проектами, это также помогает с временем компиляции, отделяя то, как это работает, от людей, которые пишут с вами, которым не нужно с этим связываться и т. Д.

Частные члены должны в основном защищать свое будущее от своего прошлого. Так что ... скажем, вы пишете класс, у которого есть метод, который возвращает, сколько денег имеет сотрудник.

int Employee::GetDollars(int employee_id); 

Вы называете это. Все, что он делает, это возвращает частную переменную данных int Dolls в классе, возможно, в духе return доллары [employee_id]; Теперь, в будущем, если вы измените то, как выясняете, какой employee_id получает какого сотрудника или что-то еще, вы должны изменить его только в одном месте. Вместо того, чтобы просто использовать classname.dollars [id], потому что тогда вам придется менять его в каждой точке вашей программы, которую вы когда-либо использовали!

0 голосов
/ 18 февраля 2011

Тебе действительно нужно учиться еще! давайте начнем с членов закрытый член означает, что вы можете получить к нему доступ, прочитать его, изменить его любым способом, не входя в класс Защищенный член означает то же самое, но вы также можете получить к нему доступ через наследование (читайте наследование действительно позже) Публичный означает ... хорошо, что вы можете получить к нему доступ из любого, где вы хотите. В небольших программах это не имеет значения, но если вы работаете в команде с 10 или 100 программистами, вы, вероятно, хотите, чтобы некоторые вещи были оставлены как есть и не могли изменить все, что вы хотите.

классы написаны таким образом, потому что это путь C ++, правда в том, что часть, где вы определяете свой класс -> class square {}; это описание класса. Вы разрабатываете свой класс и определяете членов класса. и затем, после того, как компилятор узнает, какой член принадлежит к какому классу, он переходит к фактической реализации и использует фактические члены, поэтому вам будет лучше понять, если вы используете файлы .h в своей программе заголовок - это то, где вы создаете свое столкновение, а затем в cpp, который включает в себя .h, вы фактически используете методы и значения переменных

и лучшая часть это деструкторы. Вам нужны деструкторы для удаления объектов, когда экземпляр класса удаляется. Удаление объектов - это часть программирования, которая нуждается в хорошей основе для выделения и освобождения памяти. я должен предложить книгу, которая мне очень помогла книга: «Мышление в C ++» Мой совет, продолжайте кодировать, несмотря ни на что! если вы что-то получаете в стеке, попробуйте найти примеры, если вы все еще не можете решить проблему, сделайте перерыв и повторите попытку позже

Наслаждайтесь!

0 голосов
/ 18 февраля 2011

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

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

В этом вопросе есть еще деструктор . Если вас не устраивает деструктор C ++, вы можете прочитать о памяти на C ++ в хорошей книге по C ++, такой как Accelerated C ++.

0 голосов
/ 18 февраля 2011

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

Вам не нужны частные члены.Классы предоставляют способ организовать ваш код в логическую единицу.Делая членов закрытыми, вы инкапсулируете эту логику в своем классе.Преимущество заключается в том, что вы можете сосредоточиться на этих частных участниках, не беспокоясь о том, что делают другие части вашего приложения, потому что никакая другая часть приложения не будет иметь прямого доступа к этим участникам.

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