enum или boolean члены класса что лучше?

268
28 марта 2017, 13:48

Продолжаю штудировать самоучитель Шилтда и обратил внимание что в одном из своих примеров он объевляет enum список для членов класса, которые во многих других языках программирования были бы просто булево свойствами:

// Fruit.h
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;

enum yn {no, yes};
enum color {red, yellow, green, orange};
class Fruit {
public:
    enum yn annual;
    enum yn perennial;
    enum yn tree;
    enum yn tropical;
    enum color color;
    char name[40];
};
class Apple : public Fruit{
    enum yn cooking;
    enum yn crunchy;
    enum yn eating;
public:
    void seta(char*, enum color, enum yn, enum yn, enum yn);
    void show();
};
class Orange : public Fruit {
    enum yn juice;
    enum yn sour;
    enum yn eating;
public:
    void seto(char*, enum color, enum yn, enum yn, enum yn);
    void show();
};

// Fruit.cpp
#include "Fruit.h"
char* c[] =
{
    "red", "yellow", "green", "orange"
};
void out(enum yn);
void Apple::seta(char *name, enum color color, enum yn cooking, 
enum yn  crunchy, enum yn eating)  
{
    strcpy(this->name, name);
    annual = no;
    perennial = yes;
    tree = yes;
    tropical = no;
    this->color = color;
    this->cooking = cooking;
    this->crunchy = crunchy;
    this->eating = eating;
}
void Orange::seto(char *name, enum color color, enum yn juice, 
enum yn sour,  enum yn eating)
{
    strcpy(this->name, name);
    annual = no;
    perennial = yes;
    tree = yes;
    tropical = yes;
    this->color = color;
    this->juice = juice;
    this->sour = sour;
    this->eating = eating;
}
void Apple::show()
{
    cout << name << " яблоко — это: " << "\n";
    cout << "Однолетнее растение: "; out(annual);
    cout << "Многолетнее растение: "; out(perennial);
    cout << "Дерево: "; out(tree);
    cout << "Тропическое: "; out(tropical);
    cout << "Цвет: " << c[color] << "\n";
    cout << "Легко приготавливается: "; out(cooking);
    cout << "Хрустит на зубах: "; out(crunchy);
    cout << "Съедобное: "; out(eating);
    cout << endl;
}
void Orange::show()
{
    cout << name << " яблоко — это: " << "\n";
    cout << "Однолетнее растение: "; out(annual);
    cout << "Многолетнее растение: "; out(perennial);
    cout << "Дерево: "; out(tree);
    cout << "Тропическое: "; out(tropical);
    cout << "Цвет: " << c[color] << "\n";
    cout << "Годится для приготовления сока: "; out(juice);
    cout << "Кислый: "; out(sour);
    cout << "Съедобное: "; out(eating);
    cout << endl;
 }
 void out( enum yn x)
 {
      if (x == no) cout << "нет" << endl;
      else cout << "да" << endl;
 };

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

Дополнительные вопросы, если позволите 2.1 Стоит ли в данном случае делать метод out inline методом? 2.2 Стоит ли прислушиваться к предупреждениям компилятора и избегать использования strcpy, заменив его yf strcpy_с? От каких опасностей он пытается меня предостеречь?

Answer 1

Никакого отношения к экономии памяти это не имеет.

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

foo(..., true, false, false, false, true, ...);

трудночитаем, ибо назначение каждого параметра в точке вызова ясно не сразу. Если же придать таким параметрам свои отдельные enum типы с именованными членами (даже если эти параметры по сути - просто "булевские"), то вызов функции будет читаться легче

foo(..., ENABLE_IO, NO_LOG, NO_ABORT, DISABLE_CACHE, YES_SORT, ...);

или с использованием scoped enums

foo(..., IO::ENABLE, LOG::NO, ABORT::NO, CACHE::DISABLE, SORT::YES, ...);

Также контроль типов при использовании этого приема защищает вас от указания аргументов в неправильном порядке (т.е. например от случайного "сдвига" цепочки аргументов влево или вправо).

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

P.S. const - нужен

const char* c[] =
{
    "red", "yellow", "green", "orange"
};

Как, впрочем, и в множестве других мест.

Answer 2

возможно таким образом автор избегает создание новых сущностей и экономит память

Никакой экономии памяти тут нет. Есть только наглядность. Делайте так, как вам удобней (например, enum будет полезен, если потом захочется его расширить до { no, yes, maybe, ... })

Стоит ли в данном случае делать метод out inline методом?

Почему бы и нет? В любом случае спецификатор inline - не строгое указание компилятору, он может поступить по-своему. А вот расположение кода внутри определения класса может быть просто наглядней, особенно если там одна-две строчки.

От каких опасностей он пытается меня предостеречь?

От случайного переполнения строки назначения.

Answer 3

В некоторых ситуациях enum может оказаться лучше bool: если вам вдруг захотелось добавить к набору значений maybe, unknown или что-либо в этом духе. Не думаю, что тут экономится память.

READ ALSO
Фильтрация на web-ресурсе с помощью JS

Фильтрация на web-ресурсе с помощью JS

Мне необходимо сделать фильтрацию по авторам статей на новостном порталеДолжен быть один пункт с undefined фильтром для отображения статей,...

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

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

Нужно сделать объект, который будет наследовать имя из своего прототипаНадо пропустить первый параметр, но не знаю как

284
bootstrap 4 popover js ошибка

bootstrap 4 popover js ошибка

Сначала делаю фокус в input и если следующий клик это label для этого инпута, то вылетает ошибка в консоль:

298
Можно ли на стороне клиента подменить window.location.href?

Можно ли на стороне клиента подменить window.location.href?

Доброго времени суток, господа! Нужно передать в php параметр - текущую ссылку(изначально загруженную), используя windowlocation

328