Как я могу использовать экземпляр последнего класса в коде, если он создан на основе условий ранее, в C ++ - PullRequest
1 голос
/ 29 февраля 2020

Я получаю ошибку при доступе к объекту, который я объявил на основании условий if. (LudoPlayer - это класс) Код:

if(n==4){
    cin>>a >>b >>c >>d;
    LudoPlayer play(a, b, c, d);
        }
if(n==3){
    cin>>a >>b >>c;
    LudoPlayer play(a, b, c);
        }
play.Dispaly();

Ошибка: ошибка: 'play' не было объявлено в этой области

Ответы [ 4 ]

1 голос
/ 29 февраля 2020

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

Один из подходов состоит в том, чтобы использовать функцию установки:

LudoPlayer play;
if (n == 3) {
    play.set(1, 2, 3);
} else if (n == 4) {
    play.set(1, 2, 3, 4);
}

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

LudoPlayer play;
if (n == 3) {
    play = LudoPlayer(1, 2, 3);
} else if (n == 4) {
    play = LudoPlayer(1, 2, 3, 4);
}

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

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

Вместо этого вы можете выполнить соответствующую инициализацию при создании объекта:

LudoPlayer play = (n == 3) ? LudoPlayer(1, 2, 3) : LudoPlayer(1, 2, 3, 4);

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

LudoPlayer build(int n) {
    if (n == 3) {
        return LudoPlayer(1, 2, 3);
    } else if (n == 4) {
        return LudoPlayer(1, 2, 3, 4);
}

, когда вы создаете объект, просто вызовите фабричную функцию:

LudoPlayer play(build(n));

И, да, это требует, чтобы тип будучи построенным, имеет конструктор перемещения. Если вы траффируете c в не копируемых и неподвижных типах, у вас есть множество проблем помимо всего этого.

Что касается этой фабричной функции, то для чего-то такого простого это хорошо. Но если что-то происходит, легко потеряться. Я часто нахожу, что я редактирую не то место в этой if ... else if ... лестнице. Поэтому напишите отдельные функции:

LudoPlayer build3() {
    return LudoPlayer(1, 2, 3);
}

LudoPlayer build4() {
    return LudoPlayer(1, 2, 3, 4);
}

LudoPlayer build(int n) {
    if (n == 3) {
        return build3();
    } else if (n == 4) {
        return build4();
    }
}

Или напишите диспетчеру с оператором switch:

LudoPlayer build(int n) {
    switch(n) {
    case 3: return build3();
    case 4: return build4();
    }
}

В этом случае ваш компилятор может жаловаться на отсутствие оператора default. Должен ли он быть, зависит от контекста. Если значение n не было проверено, добавьте default, который обрабатывает ошибку соответствующим образом. Если он уже был проверен, не добавляйте избыточный default. Вы знаете свой код лучше, чем компилятор; отключи глупые предупреждения.

1 голос
/ 29 февраля 2020

Два других ответа будут работать (хотя есть небольшая ошибка, ответ Хазем Абазы: указатель должен быть сначала определен вне блока if). Вы часто не можете использовать опцию из ответа adrisui3, хотя, в зависимости от того, как определен конструктор.

Другой вариант - создать функцию, которая возвращает LudoPlayer (Это может быть бесплатная функция или, возможно, лучше, член c член)

LudoPlayer makeLudoPlayer(int n) {
  if (n == 4) {
    int a, b, c, d;
    std::cin >> a >> b >> c >> d;
    return LudoPlayer(a, b, c, d);
  }
  else {
    int a, b, c;
    std::cin >> a >> b >> c;
    return LudoPlayer(a, b, c);
  }
}

//Then, main may look like this:
int main() {
  int n = 3; // or 4
  LudoPlayer play = makeLudoPlayer(n);
  play.Display();
}

0 голосов
/ 29 февраля 2020

Это похоже на ответ Бенробертса 99, но использует IIFE https://www.bfilipek.com/2016/11/iife-for-complex-initialization.html, поэтому сложная конструкция может быть выполнена в линию

int main() {
  int n = 3; // or 4

  LudoPlayer play = [](int n) {
      if (n == 4) {
        int a, b, c, d;
        std::cin >> a >> b >> c >> d;
        return LudoPlayer{a, b, c, d};
      }
      else {
        int a, b, c;
        std::cin >> a >> b >> c;
        return LudoPlayer{a, b, c};
      }
    }(n);  // pass the argument in

  play.Display();
}
0 голосов
/ 29 февраля 2020

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

LudoPlayer play;

if(n==4)
{
    cin>>a >>b >>c >>d;
    play.setValues(a, b, c, d);
}

if(n==3)
{
    cin>>a >>b >>c;
    play.setValues(a,b,c)
}

play.Dispaly();

Помните, что вам нужно использовать параметры по умолчанию в LudoPlayer :: setValues ​​(), а также создать конструктор. без параметров, в которых вы бы указали значение по умолчанию для каждого элемента данных.

Надеюсь, это было полезно. Если вам нужна дополнительная помощь, просто дайте мне знать!

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