Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

11.12.2010, 11:43

Problem bei Klassenvererbung

Hallo,
ich habe mir vorgenommen, dass ich mir ein kleines Programm-Kit zusammenbastel, damit nicht immer für jedes neue Projekt für kleinere Aufgaben relativ viel Zeit verschwenden muss. So habe ich eine kleine Klasse für das Erstellen und verwalten eines API-Fenster geschrieben.
Diese funktioniert prächtig, allerdings gibt es Probleme beim Vererben. Sobald ich die Klasse nämlich vererbt habe, spuckt mir der Compiler diese Fehlermeldung aus:

C-/C++-Quelltext

1
Unbehandelte Ausnahme bei 0x00000000 in directX_First.exe: 0xC0000005: Access violation.
. Ich schließe daraus, dass etwas mit meiner Speicherverwaltung nicht stimmt. Allerdings finde ich keinen Fehler.

Ich poste mal die Klasse (und kommentiere sie für euch aus)
Basisklasse:

Deklaration:

C-/C++-Quelltext

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
29
30
31
32
33
34
35
36
37
38
#pragma once
//-----------------------------------------------------------------//
// Includes 
//-----------------------------------------------------------------//
#include <Windows.h>
#include <pkString.h> // weitere Klasse meines Programm-Kit's. (An dieser Klasse kann es aber nicht liegen (Denn auch ohne ihr erscheint der selbe Fehler
 
//-----------------------------------------------------------------//
// Klasse: pkWindow  
//-----------------------------------------------------------------//
 
class pkWindow
{
public:
MSG msg;
 
//Konstruktor:
pkWindow();
pkWindow(int, int, pkString, WNDPROC);
pkWindow(int, int, WNDPROC);
pkWindow(pkString,  WNDPROC);
 
~pkWindow();
 
bool Init();
bool Show();
virtual void WindowLoop();
 
protected:
WNDCLASSEX wndclass;
HWND hWnd;
HINSTANCE hInstance;
 
int height, width;
pkString title;
 
WNDPROC WinProc;
};

Definition:

C-/C++-Quelltext

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//-----------------------------------------------------------------//
// Includes 
//-----------------------------------------------------------------//
 
#include <ProKit.h>
 
//-----------------------------------------------------------------//
// Klassendefinition: pkWindow 
//-----------------------------------------------------------------//
 
pkWindow::pkWindow()
: width(50), height(50), title("pkWindow")
{}
 
pkWindow::pkWindow(int _width, int _height, pkString _title, WNDPROC _WinProc)
: width(_width), height(_height), title(_title)
{
 WinProc = _WinProc;
}
 
pkWindow::pkWindow(int _width, int _height, WNDPROC _WinProc)
: width(_width), height(_height), title("PkWindow")
{
 WinProc = _WinProc;
}
 
pkWindow::pkWindow(pkString _title, WNDPROC _WinProc)
: width(50), height(50), title(_title)
{
 WinProc = _WinProc;
}
 
pkWindow::~pkWindow()
{}
 
bool pkWindow::Init()
{
//Fenstereigenschaften:
wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = WinProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.lpszClassName = L"First API";
wndclass.lpszMenuName = 0;
wndclass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
 
if (!RegisterClassEx(&wndclass))
 return false;
return true;
}
 
bool pkWindow::Show()
{
if (!(hWnd = CreateWindowEx(NULL,
L"First API",
title.toLPCWSTR(),
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0,
width, height,
NULL, NULL,
hInstance,
NULL)))
return false;
 
return true;
}
 
void pkWindow::WindowLoop()
{/*Auskommentiert, da hier kein Fehlerrisiko besteht*/}


Unterklasse mit einer außerhalb der Klasse definierten Funktion:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
LRESULT __stdcall WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){/*Auskommentiert, da hier kein Fehlerrisiko besteht*/}
 
class GShell : public pkWindow
{
public:
GShell(int _width, int _height, pkString _title)
: pkWindow(_width, _height, _title, WinProc)
{}
};

Und schließlich das Programm:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//Includes
#include <Windows.h>
#include "InitWindow.h"
 
 
//Main-Funktion
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE preInstance, LPSTR lpCmdline, int command)
{
GShell win(800, 600, "GShell");

if (!win.Init())
return 1;
 
if(!win.Show()) //Hier müsste das Problem sein!!!
{
MessageBox(NULL, L"Fehler", L"Fehler", NULL);
return 1;
}
win.WindowLoop();
 
return 0;
}


Wie gesagt, bei direkter Instanziierung, also nicht über den Umweg der Abgeleiteten Klasse, gibt es keine Probleme.
Kann mir jemand weiterhelfen?

n0_0ne

1x Contest-Sieger

  • Private Nachricht senden

2

11.12.2010, 12:08

Sieht nach einem einfachen Nullpointer aus... was spricht dagegen den Debugger anzuwerfen?

3

11.12.2010, 12:16

Ja das Problem scheint an pkWindow :: Show() bzw. an CreateWindowEx zu liegen. Wahrscheinlich dann auch an hInstance. Was habe ich falsch gemacht?

4

11.12.2010, 17:17

Hm. Es scheint wohl so, dass ich das Projekt mit dem ProKit hochladen müsse, damit mir einer helfen kann. Ist natürlich kein Problem. Im Anhang könnt ihr euch die den Zip-Ordner herunterladen.
»GreenPepper« hat folgende Datei angehängt:

denjo

Treue Seele

Beiträge: 163

Wohnort: BLB

  • Private Nachricht senden

5

11.12.2010, 17:29

Vielleicht liegt es an dem hInstance-Member. Denn so wie ich das sehe übergibst du diesen Parameter keinem der Konstruktoren und hInstance ist somit ungültig.
"Irren ist menschlich, Vergeben göttlich."
- Alexander Pope -

6

11.12.2010, 17:38

sorry, auch wenn ich die Instance Variable übergebe, gibt es das selbe Problem.

7

11.12.2010, 19:27

Aha, jetzt habe ich den Fehler nach längeren Forschungen ausfindig machen können:
ich habe eine außerhalb der Klasse definierte Funktion einfach als Argument an die Basisklasse übergegeben. Anscheinend konnte der Compiler damit nichts anfangen.
Vorher:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
LRESULT __stdcall WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{/*auskommentiert*/}

class GShell : public pkWindow
{
public:
    GShell(int _width, int _height, pkString _title)
        : pkWindow(_width, _height, _title, WinProc)
    {}
};


So nachher:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
LRESULT __stdcall WinProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{/*kommentiert*/}

class GShell : public pkWindow
{
public:
    GShell(int _width, int _height, pkString _title, WNDPROC WndProc)
        : pkWindow(_width, _height, _title, WndProc)
    {}
};


Die Entdeckung war aber eher ein Zufall und ehrlich gesagt weiß ich nicht genau warum der vorherige Code falsch war. Kann mir jemand weiterhelfen?

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

11.12.2010, 19:46

Du solltest Dir eventuell nochmal überlegen, ob du den Parameter der Methode wirklich äquivalent benennen willst wie eine real existierende Funktion. Das führt irgendwann nur zu Verwechslung und Ärger. Ein kleiner Anfangsbuchstabe würde schon einen schön sichtbaren Unterschied machen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

9

11.12.2010, 20:03

meinst du den Parameter WNDPROC WndProc?
Ich habe leider noch wenig Erfahnung mit Projekten von über 3000 Zeilen. Da kann ich solche Tipps immer gut gebrauchen.
Danke!

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

10

12.12.2010, 09:59

Ja, den meinte ich. Du solltest Dir eventuell auch eine Regel schaffen, welche Schreibweise (Notation) für lokale Variablen, für Parameter, Methoden, private Attribute, etc. verwendet werden sollen. Das vereinfacht die Erfassung der Bereichsgültigkeit deiner Variablen. Nicht jeder wird Dir hierbei zustimmen, da es teilweise gegen gewisse Konzepte geht. Aber im Endeffekt sollte Code einheitlich sein, egal ob nun durch spezielle Benennungs-Vorschriften eine Bereichsgültigkeit ablesbar ist oder nicht.
"WndProc" als Parameter ist in Deinem Fall der einzige, welcher nicht mit einem Unterstrich beginnt und groß geschrieben ist. Da ich aber zusätzlich vermute, dass du private Member-Variablen ebenfalls klein mit einem Unterstrich führst, würde ich dazu raten die Unterstriche in den Namen der Parameter wegzulassen.
Ganz speziell kommt mit bei Deiner Art der Notation der Verdacht, dass Dir das Prinzip von Parametern noch nicht 100%ig klar ist, da diese scheinbar immer exakt wie die entweder übergebenen Werte oder aber die internen Attribute benannt zu sein scheinen.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

Werbeanzeige