Форум программистов, компьютерный форум CyberForum.ru

Перечисление для дурака - C++

Восстановить пароль Регистрация
 
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
18.08.2012, 23:34     Перечисление для дурака #1
Здравствуйте.
Начал писать карточную игру в дурака, возник вопрос (ну или проблема, как угодно).

Пишу я, допустим класс карты:
C++
1
2
3
4
5
6
7
class Card {
public:
    enum suit { HEARTS, SPADES, DIAMONDS, CLUBS };
    Card( suit );
private:
    suit s;
};
Появляется стойкой ощущение, что я что-то делаю не так.
Как толково поступить с этим самым перечислением?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.08.2012, 23:34     Перечисление для дурака
Посмотрите здесь:

Перечисление в BC++ C++
Защита от дурака C++
C++ Защита от дурака
защита от дурака C++
Метод защиты от дурака C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.08.2012, 00:39     Перечисление для дурака #2
Всё правильно сделал.

Почему такое ощущение возникло? Что именно смущает?
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
19.08.2012, 00:56  [ТС]     Перечисление для дурака #3
Не знаю, подсознательно. А может и потому, что почему-то не могу создать объект вроде
C++
1
Card c( HEARTS );
DU
1477 / 1053 / 45
Регистрация: 05.12.2011
Сообщений: 2,279
19.08.2012, 01:00     Перечисление для дурака #4
может так?
C++
1
Card c(Card::HEARTS);
Mиxaил
 Аватар для Mиxaил
530 / 435 / 37
Регистрация: 10.12.2009
Сообщений: 1,857
19.08.2012, 01:02     Перечисление для дурака #5
Может, такое извращение подойдет?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Card
{
    public:
        enum suit { HEARTS, SPADES, DIAMONDS, CLUBS };
        Card( suit _s ) : s( _s ) {}
    private:
        suit s;
}; 
 
int main( int argc, char **argv )
{
    Card s( Card::HEARTS );
    return 0;
}
или
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
enum suit { HEARTS, SPADES, DIAMONDS, CLUBS };
 
class Card
{
    public:
        Card( suit _s ) : s( _s ) {}
    private:
        suit s;
}; 
 
int main( int argc, char **argv )
{
    Card c( HEARTS );
    return 0;
}
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
19.08.2012, 01:08  [ТС]     Перечисление для дурака #6
DU, Mиxaил, согласен, но это выглядит как-то убого с точки зрения проектирования класса.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.08.2012, 01:13     Перечисление для дурака #7
Цитата Сообщение от vortexx1 Посмотреть сообщение
Не знаю, подсознательно. А может и потому, что почему-то не могу создать объект вроде
C++
1
Card c( HEARTS );
Цитата Сообщение от DU Посмотреть сообщение
может так?
C++
1
Card c(Card::HEARTS);
Вот, показали, как правильно передавать такой аргумент.

Перечисления, внутренние классы, тайпдефы — всё это тоже является членами класса, так что к ним можно обращаться без квалификатора Card:: только внутри этого же класса (или с помощью using).

Всё правильно сделали, что засунули масть в класс карт, она ж ведь относится только к картам. Ей именно там и место, отнюдь не вне класса. Не забывайте только писать Card:: вне определения членов класса. То есть и при использовании, и в сигнатурах методов, описываемых вне класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
Card foo(Card::HEARTS); // вот так создавать
 
// внешнее определение метода
Card::Suit Card::getSuit() const
{
  return theSuit;
}
 
// но если бы это было внутри, то можно не писать квалификатор
class Card {
  // ...
  Suit getSuit() const { return theSuit; }
};
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
19.08.2012, 10:38  [ТС]     Перечисление для дурака #8
Дабы не плодить нехороший код и множество похожих тем, спрошу прямо здесь.
Вот что у меня пока есть:

Класс Card
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Card.h
 
class Card {
public:
    enum Suit  { HEARTS, CLUBS, DIAMONDS, ACES };
    enum Value { SIX = 6, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE };
       
    Card( Suit, Value );
    
    void setSuit( Suit );
    Suit suit() const;
    
    void setValue( Value );
    Value value() const;
 
private:
    Suit suit_;
    Value value_;
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Card.cpp
 
#include "Card.h"
 
Card::Card( Card::Suit s, Card::Value v ) : suit_( s ), value_( v ) {
            
}
 
void Card::setSuit( Card::Suit s ) {
    suit_ = s;
}
 
Card::Suit Card::suit() const {
    return suit_;
}
 
void Card::setValue( Card::Value v ) {
    value_ = v;
}
 
Card::Value Card::value() const {
    return value_;
}

и класс Deck (колода)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Deck.h
 
#include "Card.h"
#include <vector>
using namespace std;
 
class Deck {
public:
    Deck();
    
    void shuffle();
    Card getCard();
    
    int getSize() const;
       
private:
    vector< Card > deck;   
};
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// Deck.cpp
 
#include "Deck.h"
#include <algorithm>
 
Deck::Deck() {
    for( Card::Suit s = Card::HEARTS; s <= Card::ACES; ++s )
        for( Card::Value v = Card::SIX; v <= Card::ACE; ++v ) {
            Card c( s, v );
            deck.push_back( c );
        }
}
 
void Deck::shuffle() {
    random_shuffle( deck.begin(), deck.end() );
}
 
Card Deck::getCard() {
    Card c = deck.back();
    deck.pop_back();
    
    return c; 
}
 
int Deck::getSize() const {
    return deck.size();
}


Так вопрос вот в чем: эта штука не компилируется, говорит что в конструкторе Deck не определен operator++ для s и v. Как сделать это нормально?
Жутко не хочется делать уродливые (в данном случае) циклы вроде ОТ 0 ДО 3, а потом приводить типы.
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.08.2012, 11:53     Перечисление для дурака #9
Чтоб и коротко/быстро и нормально — никак. enum в Си++ не может итерироваться. Остаётся три пути:

1. +1 и приводить типы (можно спрятать
вот так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
 
class Card {
public:
    enum Suit  { HEARTS, CLUBS, DIAMONDS, ACES };
    enum Value { SIX = 6, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE };
    // ...
};
 
Card::Value& operator++(Card::Value &value)
{
  value = static_cast<Card::Value>(static_cast<int>(value) + 1);
  return value;
}
 
Card::Value operator++(Card::Value &value, int)
{
  Card::Value old_value = value;
  value = static_cast<Card::Value>(static_cast<int>(value) + 1);
  return old_value;
}
 
int main()
{
  for (Card::Value i = Card::SIX; i <= Card::ACE; ++i) {
    std::cout << i << std::endl;
  } 
}
, но сути это меняет).
2. Энтерпрайз-стайл-решение — свой класс Enum с преферансом и блудницами.
3. Запихнуть энумы в вектор:
C++
1
2
3
4
5
6
7
8
9
10
11
12
class Card {
public:
  enum Value { SIX = 6, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE };
  // ...
  static const std::vector<Value>& getValueList() { return values; }
  // ...
private:
  static std::vector<Value> values;
};
 
// C++11 фишка, к сожалению. Для неподдерживающих придётся городить костыли.
std::vector<Card::Value> Card::values({ SIX, SEVEN, EIGHT, NINE, TEN, JACK, QUEEN, KING, ACE });
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
19.08.2012, 12:08  [ТС]     Перечисление для дурака #10
Цитата Сообщение от ~OhMyGodSoLong~ Посмотреть сообщение
enum в Си++ не может итерироваться
Печально, выглядело бы эстетично.

А что если так?
C++
1
2
3
4
5
6
7
8
9
10
11
12
#define HEARTS_ 0
#define ACES_   3
#define SIX_    6
#define ACE_   14
 
Deck::Deck() {
    for( int s = HEARTS_; s <= ACES_; ++s )
        for( int v = SIX_; v <= ACE_; ++v ) {
            Card c( (Card::Suit)s, (Card::Value)v );
            deck.push_back( c );
        }
}
defer
秘密
 Аватар для defer
555 / 235 / 3
Регистрация: 29.11.2010
Сообщений: 783
19.08.2012, 12:23     Перечисление для дурака #11
В С++11 есть enum class
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.08.2012, 12:41     Перечисление для дурака #12
Цитата Сообщение от vortexx1 Посмотреть сообщение
Печально, выглядело бы эстетично.

А что если так?
А чем это принципиально отличается от варианта со static_cast<>? Длина кода — не аргумент. Если уж об эстетичности, то чем предложенный выше вариант с реализацией operator++ неэстетичен? У него только два недостатка: он не работает для не непрерывных энумов (где значения идут не последовательно) и он вызывает undefined behavior при увеличении крайнего значения на единицу.

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

Цитата Сообщение от defer Посмотреть сообщение
В С++11 есть enum class
Есть-то есть, но он (афаик) не решает проблему итерирования по энумам. Только запрещает их приводить к интам, чтобы нечаянно не привести инт к совершенно другому энуму и т. п.
vortexx1
 Аватар для vortexx1
6 / 6 / 2
Регистрация: 06.03.2011
Сообщений: 269
19.08.2012, 13:43  [ТС]     Перечисление для дурака #13
А чем это отличается от варианта со static_cast<>?
Тем, что я static_cast еще не умею
Buckstabue
 Аватар для Buckstabue
175 / 124 / 6
Регистрация: 12.01.2012
Сообщений: 624
19.08.2012, 14:26     Перечисление для дурака #14
А почему бы просто не создать статический константный массив, содержащий char * строки? "Статический" ещё в смысле общий для всех объектов класса.
Нам ведь не важно как называются масти, а важно знать, что их всего четыре вида. А в этом случае мы храним и количество видов мастей, и их названия
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.08.2012, 14:55     Перечисление для дурака
Еще ссылки по теме:

C++ Защита от дурака
C++ Защита от дурака
C++ Защита от дурака

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
OhMyGodSoLong
~ Эврика! ~
 Аватар для OhMyGodSoLong
1234 / 983 / 42
Регистрация: 24.07.2012
Сообщений: 2,002
19.08.2012, 14:55     Перечисление для дурака #15
Это называется «stringly-typed программирование».

Когда надо создать карту определённой масти, мы будем писать Card("Hearts")? Или Card(0)? А что, если надо масти выводить по-английски, по-русски, по-немецки, псевдографическими символами и картинками? Вот потому-то легче сделать пачку std::map<Card::Suit, std::string> и потом писать toASCII[SPADE] и всё.
Yandex
Объявления
19.08.2012, 14:55     Перечисление для дурака
Ответ Создать тему
Опции темы

Текущее время: 02:35. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru