c ++ Установка переменной указателя в родительском классе из дочернего и использование ее в родительском классе - PullRequest
1 голос
/ 24 февраля 2011

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

class App
{
public:
    virtual void init(void)         { window = &BasicWindow(); }
    virtual void createWindow(void) { window->create(); }

protected:
    Window *window;
};  

class Game : public App
{
public:
    virtual void init(void)         { window = &OpenGLWindow(); }
};

int main ()
{
    App *game = &Game();
    game->init();
    game->createWindow();
    return 0;
}

Это законно? У меня есть абстрактный класс Window, из которого происходит BasicWindow и OpenGLWindow. Однако, когда я создаю окно, я получаю ошибку Access violation reading location с ошибкой window->create() внутри функции App::createWindow().

Спасибо

Ответы [ 4 ]

4 голосов
/ 24 февраля 2011

Я предполагаю, что это потому, что вы указываете на временное значение:

window = &BasicWindow()

Как только эта функция завершается, window указывает на "дерьмо", и происходят плохие вещи.

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

window = new BasicWindow();

Не забудьте очистить!

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

Я собираюсь сделать вывод, что ты из Objective-C?;)

Я думаю, что все ваши проблемы связаны с непониманием того, как создаются объекты C ++.

Прежде всего: window = &BasicWindow(); - это не то, как вы должны создавать новый объект.Вам нужно использовать window = new BasicWindow; Это приводит к тому, что для BasicWindow выделяется место в памяти, и вызывается конструктор по умолчанию для BasicWindow.

В вашем методе main () есть похожая ошибка, однако в этомЕсли вам не нужно использовать new для его выделения, вы можете просто объявить экземпляр, и он будет создан в стеке.

Ваш основной метод будет выглядеть следующим образом:

int main ()
{
    Game game;
    game.createWindow();
    return 0;
}

Оставшаяся проблема в том, что ваши методы init не вызываются.В C ++ конструкторы вызываются автоматически и имеют то же имя, что и класс.Пример конструктора по умолчанию для игрового класса:

Game()  { window = new OpenGLWindow(); }

Еще одна вещь, которую вам нужно знать, это то, что, в отличие от цели C, вся иерархия конструкторов вызывается автоматически при создании объекта.То есть, когда вы создаете экземпляр Game, вызывается его конструктор, а также конструктор каждого базового класса.Фактически, конструктор базового класса называется FIRST.Так что в вашем случае, если вы просто измените методы init на конструкторы, вы выделите два окна (по одному для каждого типа) и пропустите BasicWindow.Что не круто.

Возможно, вам следует просто оставить их с именем init и просто убедиться, что вы вызываете их сразу после создания.

В общем, попробуйте это:

class App
{
public:
    virtual void init(void)         { window = new BasicWindow; }
    virtual void createWindow(void) { window->create(); }
protected:
    Window *window;
};

class Game : public App
{
public:
    virtual void init(void)         { window = new OpenGLWindow; }
};

int main ()
{
    Game game;
    game.init();
    game.createWindow();
    return 0;
}

(и не забудьте очистить новые объекты!)

РЕДАКТИРОВАТЬ (добавлен пример с очисткой):

class App
{
public:
    App() : window( NULL )      {}
    virtual ~App()              { delete window; }
    virtual void init()         { window = new BasicWindow; }
    virtual void createWindow() { window->create(); }
protected:
    Window *window;
};

class Game : public App
{
public:
    virtual void init()         { window = new OpenGLWindow; }
};

int main ()
{
    Game game;
    game.init();
    game.createWindow();
    return 0;
}
2 голосов
/ 24 февраля 2011

window - неинициализированный указатель класса App.Потому что не там, где вы вызываете init метод.Таким образом, window->create() приводит к ошибке, когда вызывается базовый класс createWindow().

Редактировать 1 :

До сих пор каждая вещь синтаксически правильна, кромене уверен в том, что вы пытаетесь достичь.Не создавайте временные / безымянные объекты и назначайте их.Вместо этого создайте их с помощью операторов new в window = &BasicWindow(); и window = &OpenGLWindow();.Поскольку класс управляет ресурсами, вы должны следовать принципу Правило трех .Также знайте, что в операторе -

App *game = new Game();

Статический тип операнда ( App *) отличается от динамического типа ( Game *).В таком случае статический тип действует как базовый класс, и его деструктор должен быть виртуальным, иначе поведение не определено.Итак, деструктор класса App должен быть виртуальным .

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

Ошибка может быть связана с тем, что вы используете указатели на временные.

virtual void init(void)         { window = &BasicWindow(); }

Этот указатель становится недействительным после ";". Используйте «новый» вместо «&». Вам нужно вызвать game-> init (), если вы тоже хотите использовать указатель окна (даже лучше вставить в конструктор, вот для чего они).

Кроме того, совершенно законно менять защищенных членов базовых классов.

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