2011-02-24 3 views
1

제목을 유감스럽게 생각합니다. 나는 문제가있는 것 같다. 나는 초심자이고 이것이 전에 물어 본다면 미안하다. 나는 이것에 대해 솔직한 대답을 찾을 수 없었다. (내가 클래스, 포인터와 자식을 검색 할 때 부모 나 자식 포인터를 전달하는 것에 대한 결과를 얻습니다. 자식 포인터 나 부모 포인터를 전달하고 싶지 않습니다. 자식 클래스에 초기화 된 포인터를 전달하려고합니다. 부모에게). 여기서 내가하려고하는 것은 코드로 더 잘 설명됩니다.C++ 부모 클래스에서 포인터 변수를 자식 클래스로 설정하고 부모 클래스에서 사용

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; 
} 

이것은 합법적입니까? BasicWindow와 OpenGLWindow가 파생되는 추상 Window 클래스가 있습니다. 그러나 창을 만들 때 함수 내에서 window->create()에 깨는 오류 Access violation reading location이 발생합니다.

감사

답변

4

나는 임시로 연결되어있어 이것이 추측하고있어 : 그 함수가 종료되면

window = &BasicWindow() 

, window 점을 "쓰레기"와 일어날 나쁜 일을.

는 아마도 싶은 것은 윈도우의 새로운 인스턴스를 생성하는 것입니다 - 즉

정리하는 것을 잊지 마세요

window = new BasicWindow(); 
!

+0

Omg, 나는 지금 매우 어리 석다. 고마워요! 나는 단지 하나의 창만 필요하기 때문에 클래스의 '새로운'인스턴스를 만들 필요가 없다고 생각했습니다. 하지만 '범위에서 한 번 사용'하는 부분을 오해 한 것 같습니다. – Nique

+3

@Nique, C++을 배우는 길고 힘든 길에서 우리 모두가 비슷한 실수를 범했다고 확신합니다. :) – Nim

2

window은 클래스 App의 초기화되지 않은 포인터입니다. 왜냐하면, 당신이 init 메서드를 호출하는 곳이 없기 때문입니다. 따라서 기본 클래스 createWindow()이 호출 될 때 window->create() 결과 오류가 발생합니다.

편집 1 :

는 지금까지 지금처럼 모든 일이 문법적으로 정확하지만, 당신이 달성하려고하는 무엇 amn't 확실하다. 임시/이름이없는 오브젝트를 작성하여 할당하지 마십시오. 대신 연산자 newwindow = &BasicWindow();window = &OpenGLWindow();에 구성하십시오. 학급이 자원을 관리하기 때문에 원칙 Rule of Three을 따라야합니다.

App *game = new Game(); 

피연산자의 정적 유형 (앱 *)는 동적 유형 (게임 *) 다른 - 또한 성명에서 것을 알고있다. 이 경우 정적 유형은 기본 클래스로 작동하며 소멸자는 가상이어야합니다. 그렇지 않으면 동작이 정의되지 않습니다. 따라서 App 클래스 소멸자는이어야합니다.

+0

+1 oops, 나는 그걸 너무 놓쳤습니다 !! : D, 내 대답을 떠날 것 같아, 여전히 유효하다고 생각해! – Nim

+0

죄송합니다, 상황을 재현했습니다. 사실, 나는 App-> start()에서 init()을 호출한다. – Nique

+0

@ edit 1, 나는 더 이상 주요 기능 (또는 그 밖의 다른 곳)에서 게임이 필요하지 않습니다. 정말 개체의 새 인스턴스를 만들어야합니까? 내 아카이브 : 및/모든 운영 체제에서 Windows를 만드는 객체 지향 방식. 나는이 못생긴 메시지 처리기를 메인에 넣고 싶지 않다. – Nique

1

오류는 임시 포인터에 대한 포인터를 사용하고 있다는 사실과 관련이 있습니다.

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

이 포인터는 ";"다음에 유효하지 않게됩니다. "&"대신 "new"를 사용하십시오. 윈도우 포인터도 사용하고 싶다면 game-> init()을 호출해야합니다 (생성자에 넣어두면 더 좋을 것입니다).

게다가 기본 클래스의 보호 된 멤버를 변경하는 것은 완벽합니다.

2

Objective-C에서 오는 펀트를 가져갈 것입니까? ;)

여러분의 문제는 모두 C++ 객체가 어떻게 생성되는지 이해하지 못했기 때문에 발생한다고 생각합니다.

처음으로 : window = &BasicWindow();은 새 개체를 만드는 방법이 아닙니다. window = new BasicWindow; 사용해야합니다. 이로 인해 BasicWindow가 메모리에 할당되는 공간이 생기고 BasicWindow의 기본 생성자가 호출됩니다.

main() 메서드에서 비슷한 오류가 발생하지만이 경우 new를 할당 할 필요가 없습니다. 인스턴스를 선언하면 스택에 만들어집니다.

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

나머지에 문제가 초기화 메소드가 호출되지 않는 것입니다 : 같은

귀하의 주요 방법은 다음 보일 것이다. C++에서 생성자는 자동으로 호출되며 클래스와 동일한 이름으로 지정됩니다. 게임 클래스에 대한 예제 기본 생성자는 다음과 같습니다

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

당신이 알아야 할 또 다른 한가지는 객체를 생성 할 때 객관적인 C는 달리, 생성자의 전체 계층 구조가 자동으로 호출되어 있다는 점이다. 즉, Game의 인스턴스를 만들면 모든 기본 클래스의 생성자뿐만 아니라 생성자가 호출됩니다. 실제로 기본 클래스 생성자는 FIRST라고합니다. 그래서 당신의 경우 init 메소드를 생성자로 바꾸면 두 개의 윈도우 (각각의 타입 중 하나)를 할당하고 BasicWindow를 누출하게됩니다. 멋지지 않아.

아마도 init로 이름을 지어야하고, 생성 직후에 호출해야합니다. 합니다 (new'd 오브젝트를하고 정리하는 것을 잊지 마세요!)

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; 
} 
+0

+1 좋은 답변입니다. App에 가상 소멸자를 추가하면 더 좋을 것입니다. 아마도 윈도우가 제로 포인터인지 확인한 다음 그렇지 않으면 삭제합니다. – Tom

+0

나는 객관적인 C에서 오지 않을거야. 나는 객체 지향 PHP 스크립팅에서 왔어. 나는 생성자와 소멸자에 관한 이야기를 알고있다. 하지만 부모 생성자의 윈도우 인스턴스를 변경하려고하면 혼란 스럽습니다. 그래서 이것이 바로 init() 메소드를 만든 이유입니다. 그것을 지적 주셔서 감사합니다!, 더 잘 설명하지 못했습니다. 유용한 답변을 주셔서 감사합니다. (나는 main에서 더 깔끔하게 처리한다.) game.run() .. 그리고 run은 init()과 윈도우 생성을 담당한다. – Nique

+0

@Tom 당신이 말한 것처럼 소멸자를 추가했다면 생성자가 window = NULL을 설정해야합니다. 그렇지 않으면 임의의 메모리가되며 초기화되지 않은 경우에는 0이 아닌 가능성이 높습니다. 나는 멀리 가서 위험을 혼동시킬 위험이있다. :) –

관련 문제