orsino
-
Gesamte Inhalte
33 -
Benutzer seit
-
Letzter Besuch
Inhaltstyp
Profile
Forum
Downloads
Kalender
Blogs
Shop
Beiträge von orsino
-
-
Jeff Prosise beschreibt in 'Programming Windows with MFC' eine Möglichkeit
This problem is easily solved with a message pump. Here's the proper way to execute a lengthy procedure in a single-threaded MFC program:
void CMainWindow::OnStartDrawing ()
{
m_bQuit = FALSE;
for (int i=0; i<NUMELLIPSES && !m_bQuit; i++) {
DrawRandomEllipse ();
if (!PeekAndPump ()) // PeekAndPump entspricht DoEvents
break;
}
}
void CMainWindow::OnStopDrawing ()
{
m_bQuit = TRUE;
}
BOOL CMainWindow::PeekAndPump ()
{
MSG msg;
while (::PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE)) {
if (!AfxGetApp ()->PumpMessage ()) {
::PostQuitMessage (0);
return FALSE;
}
}
LONG lIdle = 0;
while (AfxGetApp ()->OnIdle (lIdle++));
return TRUE;
}
PeekAndPump enacts a message loop within a message loop. Called at the conclusion of each iteration through OnStartDrawing's for loop, PeekAndPump first calls CWinThread::PumpMessage to retrieve and dispatch messages if ::PeekMessage indicates that messages are waiting in the queue. A 0 return from PumpMessage indicates that the last message retrieved and dispatched was a WM_QUIT message, which calls for special handling because the application won't terminate unless the WM_QUIT message is retrieved by the main message loop. That's why PeekAndPump posts another WM_QUIT message to the queue if PumpMessage returns 0, and why the for loop in OnStartDrawing falls through if PeekAndPump returns 0. If a WM_QUIT message doesn't prompt an early exit, PeekAndPump simulates the framework's idle mechanism by calling the application object's OnIdle function before returning.
funktioniert prinzipiell, habe es auch schon mal verwendet, kann aber je nach verwendung etwas umständlich werden. ich weiß nicht, ob sich dein problem so lösen lässt. vielleicht solltest du über einen worker thread nachdenken.
-
Also das mit den konstruktoren musst du dir wohl nochmal ansehen, Crush.
class bing
{
public:
bing(int x=0):zahl(0){}
virtual ~bing(){};
virtual void set(const int x){zahl=x;}
virtual int get() const {return zahl;}
private:
int zahl;
};
class ding : virtual bing
{
public:
ding(){bing::bing();}; // basis konstruktor wird zweimal aufgerufen
virtual ~ding(){bing::~bing();}; // subobject vom typ bing wird zweimal zerstört
void set(const int x){bing::set(x);}
void setown(const int x) {zahl=x;}
int get() const {return bing::get();}
int getown() const {return zahl;}
private:
int zahl;
};
ich hab mal die zwei klassen als beispiel genommen. wozu wird im ctor von ding der basis-ctor expilzit aufgerufen? wenn das programm die öffnende geschweifte Klammer des ctors von ding erreicht ist das komplette ding - objekt schon konstruiert und der basis ctor wurde bereits aufgerufen. der compiler generiert standardmäßig einen aufruf des default ctors der Basisklasse. wenn man das nicht möchte oder es nicht geht, muss man den aufruf selbst explizit in der initialisierungsliste VOR der geschweiften klammer angeben
ding() : bing("ding ruft bing") {}
// unter der annahme bing hat einen ctor bing(char* Msg);
im vorliegenden fall
ding(){bing::bing();};
wird innerhalb das anweisungsblocks ein namenloses objekt vom typ bing erzeugt, das beim verlassen des blocks sofort wieder zerstört wird (im debugger kann man den destruktor aufruf von bing verfolgen).
ähnlich ist es beim destruktor. NACHDEM ~ding() fertig ist wird automatisch ~bing() aufgerufen. der explizite aufruf innerhalb von ~ding() ist etwa so, als wollte man den keller vor dem dach abreißen.
der folgende code würde zum beispiel abstürzen
class bing
{
public:
bing(int x=0):zahl(0){pFoo = new int(10);}
virtual ~bing(){delete pFoo;}
private:
int zahl;
int *pFoo;
};
class ding : virtual bing
{
public:
ding(){bing::bing();};
virtual ~ding(){bing::~bing();}; // zweimal delete pFoo
private:
int zahl;
};
man könnte das problem umgehen
virtual ~bing(){if (pFoo) {delete pFoo; pFoo = NULL;};}
aber die eigentliche logik ist nicht korrekt. richtiger wäre ding so zu definieren
class ding : virtual bing
{
public:
ding(){}
virtual ~ding(){}
private:
int zahl;
};
und noch was zum goto. ich selbst hab mein letztes goto vor vielen jahren (damals noch in basic) verwendet. aber es gibt durchaus sinnvolle verwendungen, wie ich erst jetzt wieder in Tom Archers 'Inside C#' gelesen habe (ja c# hat ein goto). er beschreibt, dass der goto befehl in ungnade fiel mit der veröffentlichung des artikels 'Go To Statement Considered Harmful' (Edsger W. Dijkstra, 1968) http://www.acm.org/classics/oct95/
in einem switch block zum beispiel könnte es sinnvoll sein ein goto zu verwenden.
-
Das Makro _UNICODE wird nur für die Header-Dateien der C-Laufzeitbibliothek verwendet, das Makro UNICODE dagegen für die Win32-Header-Dateien. Normalerweise müssen beide Makros definiert sein. Ich mache das immer in Projekt-Settings bei den Präprozessor-Einstellungen. In der MSDN habe ich folgendes gefunden:
To compile code for Unicode, you need to #define UNICODE for the Win32 header files and #define _UNICODE for the C Run-time header files. These #defines must appear before the following:
#include <windows.h>
and any included C Run-time headers. The leading underscore indicates deviance from the ANSI C standard. Because the Windows header files are not part of this standard, it is allowable to use UNICODE without the leading underscore.
-
Ich hab das ganze auch mal ausprobiert und festgestellt das mit den Pointer-Addressen alles stimmt. Wenn man sich den Assembler Code (ich benutze Visual C++6 als Compiler) dazu ansieht, dann ist es eigentlich ganz leicht zu erklären. Bei der Zuweisung:
int nErgebnis = nConstWert + 50;
schreibt der Compiler
int nErgebnis = 150;
das heißt der Wert steht schon zu Beginn fest im Code. Der Compiler sieht das nConstWert als konstanter Integer 100 definiert ist und ersetzt deshalb jedes Vorkommen mit dem konkreten Wert. Jede Manipulation der Variablen während des Programms bleibt also unberücksichtigt. Dieses Verhalten ist compilerabhängig und in den Standards nicht definiert. Nach der Zeile * pAufConstWert = 50;
ist jeder Ausdruck der nConstWert benutzt nicht definiert. Ich habe auf Google einige Posts zu diesem Thema gefunden und bei einigen Compilern würde 100 und bei anderen 150 herauskommen.
Um wirklich den aktuellen Wert aus dem Speicher zu lesen müsste man in dem Fall:
int nErgebnis = *const_cast<int*>(&nConstWert) + 50;
schreiben.
-
vielleicht ist das ja auch interessant
//: C11:PmemFunDefinition.cpp
class Simple2 {
public:
int f(float) const { return 1; }
};
int (Simple2::*fp)(float) const;
int (Simple2::*fp2)(float) const = &Simple2::f;
int main() {
fp = &Simple2::f;
} ///:~
In the definition for fp2 you can see that a pointer to member
function can also be initialized when it is created, or at any other
time. Unlike non-member functions, the & is not optional when
taking the address of a member function. However, you can give
the function identifier without an argument list, because overload
resolution can be determined by the type of the pointer to member.
weiteres Beispiel:
//: C11:PointerToMemberFunction2.cpp
#include <iostream>
using namespace std;
class Widget {
void f(int) const { cout << "Widget::f()\n"; }
void g(int) const { cout << "Widget::g()\n"; }
void h(int) const { cout << "Widget::h()\n"; }
void i(int) const { cout << "Widget::i()\n"; }
enum { cnt = 4 };
void (Widget::*fptr[cnt])(int) const;
public:
Widget() {
fptr[0] = &Widget::f; // Full spec required
fptr[1] = &Widget::g;
fptr[2] = &Widget::h;
fptr[3] = &Widget::i;
}
void select(int i, int j) {
if(i < 0 || i >= cnt) return;
(this->*fptr)(j);
}
int count() { return cnt; }
};
int main() {
Widget w;
for(int i = 0; i < w.count(); i++)
w.select(i, 47);
} ///:~
Similarly, when the pointer-to-member is dereferenced, it seems
like
(this->*fptr)(j);
is also over-specified; this looks redundant. Again, the syntax
requires that a pointer-to-member always be bound to an object
when it is dereferenced.
die Beispiele sind aus dem Buch Thinking in C++ von Bruce Eckel. Kann man sich als pdf bei http://www.bruceeckel.com laden.
-
In dem Fall würde ich es in die Header Datei schreiben, zumindest die Typdefinition.Original geschrieben von TechnicianHi!
Ich hab hier folgendes Problemchen:
Eine Klasse "Kunde" soll als Attribut einen Vector enthalten, in dem Objekte der Klasse "Anlage" gespeichert werden.
Da ich noch nie mit Vector und OOP gleichzeitig zu tun hatte:
gehören die Zeilen
#include <vector> using namespace std ; typedef vector<Anlage> ANLVECTOR;
in die Header- oder CPP-Datei von "Kunde"?!ANLVECTOR myVector; ANLVECTOR::iterator myIterator;
gehören in die Headerdatei, das ist mir klar... das ist hier mal (vereinfacht) meine Kunde-Headerdatei, noch ohne Vector.//KUNDE.H #ifndef KUNDE_H #define KUNDE_H class Anlage; class Kunde { public: Kunde(char* n); ~Kunde(){}; ... private: char* seinName; Anlage* seineAnlage; //bisher nur eine Anlage, mit dem Vector werden's viele! ... }; #endif
Ich hoffe, ihr könnt mir da weiterhelfen; mit "mal rumprobieren ob's so oder so ist" is nämlich nix -> Projekt schon zu groß! Gruß, Technician//KUNDE.H #include <vector> using namespace std ; /* den vector include würde ich in das standard include stdafx.h ziehen */ #ifndef KUNDE_H #define KUNDE_H class Anlage; // Vorwärtsdeklaration typedef vector<Anlage*> ANLVECTOR; /* Muss nach der vorwärtsdeklaration von class Anlage stehen deshalb kann es auch nicht im Kunde.cpp vor dem dem Kunde.h include stehen. Und wenn es danach stehen würde, kannst du ANLVECTOR logischerweise nicht im header verwenden. Außerdem enthält der ANLVECTOR bei mir nur pointer auf anlage-objekte - macht operationen mit dem vector schneller. Wenn du wirklich komplette objekte in dem vector ablegen willst, reicht die einfache vorwärtsdeklaration nicht aus (geht nur für pointer). In diesem fall musst du vorher Anlage.h inkludieren. */ class Kunde { public: Kunde(char* n); ~Kunde(){}; ... private: char* seinName; Anlage* seineAnlage; //bisher nur eine Anlage, mit dem Vector werden's viele! ... }; #endif
-
Original geschrieben von Klotzkopp
ShellExecute startet allerdings nicht den Kommandozeileninterpreter (command/cmd), daher funktioniert
ShellExecute( NULL, "open", "dir c:\\", NULL, NULL, SW_SHOWDEFAULT );
nicht, weil dir ein interner Befehl ist, der in den Kommandozeileninterpreter eingebaut ist.
In dem Fall kann man aber den Umweg über eine .bat-Datei gehen.
so gehts
ShellExecute(NULL, "open", "cmd", "/k dir c:", NULL, SW_SHOWNORMAL );
Bewertung einsehen
in IHK-Prüfung allgemein
Geschrieben
Ich hab zwar die Prüfung hinter mir, möchte aber trotzdem mal einen Blick auf die Bewertung werfen, wo Punkte abgezogen wurden und so. Wie bekommt man diese Möglichkeit?