Как переместить определение подкласса? [Дубликат]

Что вам нужно знать:

текст, который представляет несколько строк, также содержит непечатаемые символы между строками (мы называем их разделителями строк), как возврат каретки (CR - в строковых литералах, представленных как "\r" ) line line (LF - в строковых литералах, представленных как "\n"), когда вы читаете данные с консоли, это позволяет пользователю набирать свой ответ, а когда он сделан, ему нужно как-то подтвердить этот факт. Для этого пользователю необходимо нажать клавишу «enter» / «return» на клавиатуре. Важно то, что этот ключ, помимо обеспечения помещения пользовательских данных в стандартный ввод (представлен System.in, который читается Scanner), также отправляет зависимые от ОС разделители строк (например, для Windows \r\n) после него. Поэтому, когда вы запрашиваете у пользователя значение типа age, а пользовательские типы 42 и нажимаете ввод, стандартный ввод будет содержать "42\r\n".

Проблема

Scanner#nextInt (и другие методы Scanner#nextType) не позволяет Сканеру потреблять эти разделители строк. Он прочитает их из System.in (как еще Сканер узнает, что больше нет цифр от пользователя, которые представляют age значение, чем перед пробелом?), Который удалит их со стандартного ввода, но он также будет кэшировать эти разделители строк внутренне. Нам нужно помнить, что все методы Scanner всегда сканируются, начиная с кэшированного текста.

Теперь Scanner#nextLine() просто собирает и возвращает все символы потребляют (или конец потока). Но поскольку разделители строк после прочтения номера из консоли сразу обнаруживаются в кеше сканера, он возвращает пустую строку, что означает, что сканер не смог найти символ до этих разделителей строк (или конца потока). BTW nextLine также потребляет эти разделители строк.

Решение

Итак, если вы хотите запросить номер, а затем для всей строки и избежать этой пустой строки в результате nextLine, либо

, который представляет несколько строк, также содержит непечатаемые символы между строками (мы называем их разделителями строк), как возврат каретки (CR - в строковых литералах, представленных в виде "\r") line feed (LF - в строковых литералах, представленных как "\n") не используют nextInt (ни next, ни какие-либо методы nextTYPE). Вместо этого прочитайте целые строки данных по строке nextLine и номера разбора из каждой строки (при условии, что одна строка содержит только одно число) для правильного типа, например int через Integer.parseInt.

он также будет кэшировать эти разделители строк внутри : Scanner#nextType методы могут потреблять разделители (по умолчанию все пробелы типа вкладки, разделители строк), в том числе кэшированные сканером, пока они не найдут следующее значение без разделителя (токен). Благодаря этому для ввода типа "42\r\n\r\n321\r\n\r\n\r\nfoobar" код

int num1 = sc.nextInt(); int num2 = sc.nextInt(); String name = sc.next();

сможет правильно назначить num1=42 num2=321 name=foobar.

168
задан JasonMArcher 7 June 2015 в 01:41
поделиться

6 ответов

Вы не можете этого сделать, это дыра на языке C ++. Вам нужно будет разблокировать хотя бы один из вложенных классов.

185
ответ дан Adam Rosenfield 27 August 2018 в 15:35
поделиться

Это можно сделать переадресацией, объявив внешний класс как пространство имен.

Образец: нам нужно использовать вложенный класс others :: A :: Nested in others_a.h, который не входит в нашу

others_a.h

namespace others {
struct A {
    struct Nested {
        Nested(int i) :i(i) {}
        int i{};
        void print() const { std::cout << i << std::endl; }
    };
};
}

my_class.h

#ifndef MY_CLASS_CPP
// A is actually a class
namespace others { namespace A { class Nested; } }
#endif

class MyClass {
public:
    MyClass(int i);
    ~MyClass();
    void print() const;
private:
    std::unique_ptr<others::A::Nested> _aNested;
};

my_class.cpp

#include "others_a.h"
#define MY_CLASS_CPP // Must before include my_class.h
#include "my_class.h"

MyClass::MyClass(int i) :
    _aNested(std::make_unique<others::A::Nested>(i)) {}
MyClass::~MyClass() {}
void MyClass::print() const {
    _aNested->print();
}
0
ответ дан bitlixi 27 August 2018 в 15:35
поделиться

Это было бы обходным решением (по крайней мере, для проблемы, описанной в вопросе, а не для реальной проблемы, то есть когда не было контроля над определением C):

class C_base {
public:
    class D { }; // definition of C::D
    // can also just be forward declared, if it needs members of A or A::B
};
class A {
public:
    class B { };
    C_base::D *someField; // need to call it C_base::D here
};
class C : public C_base { // inherits C_base::D
public:
    // Danger: Do not redeclare class D here!!
    // Depending on your compiler flags, you may not even get a warning
    // class D { };
    A::B *someField;
};

int main() {
    A a;
    C::D * test = a.someField; // here it can be called C::D
}
0
ответ дан chtz 27 August 2018 в 15:35
поделиться

Если вы действительно хотите избежать # включения неприятного заголовочного файла в файл заголовка, вы можете сделать это:

hpp файл:

class MyClass
{
public:
    template<typename ThrowAway>
    void doesStuff();
};

cpp file

#include "MyClass.hpp"
#include "Annoying-3rd-party.hpp"

template<> void MyClass::doesStuff<This::Is::An::Embedded::Type>()
{
    // ...
}

Но тогда:

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

Итак, да, компромиссы ...

3
ответ дан edenbridge 27 August 2018 в 15:35
поделиться
class IDontControl
{
    class Nested
    {
        Nested(int i);
    };
};

Мне нужна прямая ссылка вроде:

class IDontControl::Nested; // But this doesn't work.

Мое обходное решение было:

class IDontControl_Nested; // Forward reference to distinct name.

Позже, когда я смог использовать полное определение:

#include <idontcontrol.h>

// I defined the forward ref like this:
class IDontControl_Nested : public IDontControl::Nested
{
    // Needed to make a forwarding constructor here
    IDontControl_Nested(int i) : Nested(i) { }
};

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

Но в моем очень простом случае это работает.

27
ответ дан Marsh Ray 27 August 2018 в 15:35
поделиться

Я бы не назвал это ответом, но, тем не менее, интересной находкой: если вы повторите объявление своей структуры в пространстве имен C, все будет в порядке (по крайней мере в gcc). Когда определение класса C найдено, оно, кажется, молча перезаписывает namspace C.

namespace C {
    typedef struct {} D;
}

class A
{
public:
 typedef struct/class {...} B;
...
C::D *someField;
}

class C
{
public:
   typedef struct/class {...} D;
...
   A::B *someField;
}
0
ответ дан nschmidt 27 August 2018 в 15:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: