Forum: PC-Programmierung C++ (QT): Objekt, Zeiger, Referenz,.


von Julian W. (julian-w) Benutzerseite


Lesenswert?

Hallo,
irgendwie blick ich gerade nicht mehr ganz durch bei C++... evtl. 
könntet ihr mir hier mal auf die Sprünge helfen. Soweit bin ich 
schonmal:

Ein Objekt enthält quasi "alles", also Eigenschaften, Funktionen etc. 
und belegt dementsprechend auch Speicher.

Ein Zeiger enthält nur die Adresse auf ein Objekt. Wenn man den Zeiger 
ausliest, erhält man die Adresse. "Symbol": *

Eine Referenz enthält auch nur die Adresse eines Objektes. Jedoch kann 
man die Referenz wie ein Objekt behandeln. "Symbol": &

Nun würde ich gerne eine statische Klasse definieren, um Einstellungen 
zu speichern. Momentan sieht das wie folgt aus:

settings.h
1
#ifndef SETTINGS_H
2
#define SETTINGS_H
3
4
#include <QSettings>
5
6
class settings
7
{
8
public:
9
    static bool getSavingLoginData();
10
    static void setSavingLoginData(bool values);
11
12
    static void checkAviable();
13
    static bool settingsLoad;
14
15
    static QSettings access;
16
};
17
18
#endif // SETTINGS_H

settings.ccp
1
#include "settings.h"
2
3
4
bool settings::getSavingLoginData()
5
{
6
    checkAviable();
7
    // TODO: auslesen
8
    return false;
9
}
10
11
void settings::setSavingLoginData(bool value)
12
{
13
    checkAviable();
14
    // TODO: speichern
15
}
16
17
void settings::checkAviable()
18
{
19
    if(settingsLoad == false)
20
    {
21
        settingsLoad = true;
22
        access = new QSettings("C:/blablabla", QSettings::IniFormat);
23
    }
24
}

Nur leider erhalte ich hier einen Fehler vom kompilier:
1
settings.cpp:22: Fehler:no match for 'operator=' in 'settings::access = (((const QString&)(& QString(((const char*)"C:/blablabla")))), (operator new(8u), (<statement>, ((QSettings*)<anonymous>))))'
2
3
qsettings.h:304: candidate is: QSettings& QSettings::operator=(const QSettings&)

Ich hab schon alles mögliche probiert, also mit "*" und "&", aber 
irgendwie hat es nie funktioniert :/

Wie mache ich das am besten? Und der Umweg mit "settingsLoad" kann man 
doch bestimmt auch schöner machen und einfach direkt Prüfen, ob das 
Objekt exsistiert, oder?

In einer anderen Klasse hab ich das ganze z.B. so gelöst, was auch ohne 
Probleme funktioniert:

basic_storage.h
1
#ifndef BASIC_STORAGE_H
2
#define BASIC_STORAGE_H
3
4
5
#include "storage/sql_access.h"
6
7
namespace storage
8
{
9
10
class basic
11
{
12
13
public:
14
    basic();
15
16
    bool connect(int typ, QString server, QString db_name, QString user, QString passwd, int port);
17
    bool connect(QString path);
18
19
    bool isAuth();
20
    bool isCorrectDB();
21
22
private:
23
    storage::sql *_sql;
24
};
25
26
}
27
28
#endif // BASIC_STORAGE_H

basic_storage.cpp:
1
#include "basic_storage.h"
2
namespace storage
3
{
4
5
basic::basic()
6
{
7
}
8
9
bool basic::connect(QString path)
10
{
11
    this->_sql = new storage::sql(storage::sql::DB_SQLITE);
12
    return this->_sql->connect(path);
13
}
14
15
bool basic::connect(int typ, QString server, QString db_name, QString user, QString passwd, int port)
16
{
17
    this->_sql = new storage::sql(typ);
18
    return this->_sql->connect(server, db_name, user, passwd, port);
19
}
20
21
bool basic::isAuth()
22
{
23
    if(this->_sql == NULL)
24
    {
25
        return false;
26
    }
27
    return this->_sql->isConnected();
28
}
29
30
bool basic::isCorrectDB()
31
{
32
    QStringList *tables = this->_sql->getTables();
33
    //tables->contains("temp");
34
    return false;
35
}
36
37
}

Was mach ich also falsch???

Wäre nett, wenn mir da einer Helfen könnte...

Viele Grüße
Julian

von kaffeedoktor (Gast)


Lesenswert?

Hallo Julian,

in Deiner settings-Klasse deklarierst Du access nicht als Zeiger sondern 
als "normale" Membervariable vom Typ QSettings. In 
sessings::checkAviable() erzeugst Du dann aber mit new ein neues 
QSettings-Objekt auf dem Heap und versuchst dann den Zeiger auf dieses 
an Deine Membervariable access zuzuweisen. Deswegen meckert der 
Compiler.

In Deiner Storage-Klasse wiederum machst Du es ja richtig: _sql ist ein 
Zeiger vom Typ storage::sql. Deswegen klappt es dort auch mit dem new 
;-)

kaffeedoktor

von Julian W. (julian-w) Benutzerseite


Lesenswert?

So, jetzt hab ich mal den Header wie folgt abgeändert:
1
#ifndef SETTINGS_H
2
#define SETTINGS_H
3
4
#include <QSettings>
5
6
class settings
7
{
8
public:
9
    static bool getSavingLoginData();
10
    static void setSavingLoginData(bool values);
11
12
    static void checkAviable();
13
    static bool settingsLoad;
14
15
    static QSettings *access;
16
};
17
18
#endif // SETTINGS_H

Doch jetzt erhalte ich folgende Fehler vom Compiler:
1
settings.cpp:19: Fehler:undefined reference to `settings::settingsLoad'
2
3
settings.cpp:21: Fehler:undefined reference to `settings::settingsLoad'
4
5
settings.cpp:22: Fehler:undefined reference to `settings::access'
6
7
:-1: Fehler:collect2: ld returned 1 exit status

Die ccp-Datei hab ich nicht verändert. Kann mir dass einer erklären!?

von kaffeedoktor (Gast)


Lesenswert?

Hallo Julian,

für Deine statischen Membervarialben musst Du natürlich auch noch 
irgendwo Speicher reservieren. Bisher hast Du sie ja nur deklariert. 
Also am besten in die settings.cpp an den Anfang

bool settings::settingsLoad = false;
QSettings* settings::access = NULL;

So kannst Du sie auch gleich initialisieren.

kaffeedoktor

von Karl H. (kbuchegg)


Lesenswert?

Wobei sich die Frage erhebt:
Wenn in deiner Klasse sowieso alles static ist, wozu dann überhaupt eine 
Klasse?

von Julian W. (julian-w) Benutzerseite


Lesenswert?

kaffeedoktor schrieb:
> bool settings::settingsLoad = false;
> QSettings* settings::access = NULL;

Danke, das war's gewesen :)
Hat mich nur gewundert, dass er über "settingsLoad" sich erst beschwert 
hatte, als ich "access" als Pointer anlegte...


Karl Heinz Buchegger schrieb:
> Wenn in deiner Klasse sowieso alles static ist, wozu dann überhaupt eine
> Klasse?

Nunja, der Übersichtlichkeit wegen halt ;)
So kann ich über "settings::blablabla" auf alles schön über die 
Autovervollständigung zugreifen.

von kaffeedoktor (Gast)


Lesenswert?

Hallo Julian,

über settingsLoad hat sich der Linker beschwert, während beim Problem 
mit dem QSettings-Zeiger der Compiler gemeckert hat. Und solange der 
Compiler meckert, fängt der Linker erst garnicht das Arbeiten an.

kaffeedoktor

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Noch ne Frage zu QSettings:
Ich hab das ganze jetzt mal so umgeschrieben:

settings.h
1
#ifndef SETTINGS_H
2
#define SETTINGS_H
3
4
#include <QSettings>
5
6
class settings
7
{
8
public:
9
    static bool getSavingLoginData();
10
    static void setSavingLoginData(bool toStorage);
11
12
    static QSettings *access;
13
};
14
15
#endif // SETTINGS_H

settings.ccp
1
#include "settings.h"
2
3
QSettings* settings::access = new QSettings("J:\\repo\\lucifer\\settings.ini", QSettings::IniFormat);
4
5
bool settings::getSavingLoginData()
6
{
7
    bool result;
8
9
    access->beginGroup("general");
10
    result = access->value("savelogin", false).toBool();
11
    access->endGroup();
12
13
    return result;
14
}
15
16
void settings::setSavingLoginData(bool toStorage)
17
{
18
    access->beginGroup("general");
19
    access->value("savelogin", toStorage);
20
    access->endGroup();
21
}

Doch leider funktioniert es nicht :/
Die Datei existiert. Ob ich \\ oder / beim Pfad verwende macht keinen 
Unterschied.
Weiß einer, was ich falsch mache?

von Karl H. (kbuchegg)


Lesenswert?

Julian W. schrieb:
> Noch ne Frage zu QSettings:
> Ich hab das ganze jetzt mal so umgeschrieben:

Keine gute Idee


> QSettings* settings::access = new
> QSettings("J:\\repo\\lucifer\\settings.ini", QSettings::IniFormat);

Das wird ausgeführt, wenn das Programm hochfährt. Zu diesem Zeitpunkt 
ist aber noch lange nicht gewährleistet, dass QT überhaupt schon 
komplett und vollständig initialisiert und arbeitsfähig ist.

> Weiß einer, was ich falsch mache?

Dein Verständnis über C++ ist noch mangelhaft. Welche C++-Literatur 
benutzt du?

Wenn du von einer Klasse nur 1 einziges Objekt haben willst, dann macht 
man das nicht, indem man alle Member static macht, sondern indem man das 
Singleton Pattern anwendet (danach googeln). Dann hat man wieder im 
Konstruktor den perfekten Platz um derartige Initialisierungen 
unterzubringen.

von Julian W. (julian-w) Benutzerseite


Lesenswert?

Karl Heinz Buchegger schrieb:
> Das wird ausgeführt, wenn das Programm hochfährt. Zu diesem Zeitpunkt
> ist aber noch lange nicht gewährleistet, dass QT überhaupt schon
> komplett und vollständig initialisiert und arbeitsfähig ist.

Gut, ich habe es dann mal so umgeschrieben:
1
#include "settings.h"
2
3
QSettings* settings::access = NULL;
4
5
bool settings::getSavingLoginData()
6
{
7
    access = new QSettings("J:\\repo\\lucifer\\settings.ini", QSettings::IniFormat);
8
9
    bool result;
10
11
    access->beginGroup("general");
12
    result = access->value("savelogin", false).toBool();
13
    access->endGroup();
14
15
    return result;
16
}
17
18
void settings::setSavingLoginData(bool toStorage)
19
{
20
    access->beginGroup("general");
21
    access->value("savelogin", toStorage);
22
    access->endGroup();
23
}

Die Funktion "getSavingLoginData" wird definitiv nur einmal aufgerufen 
und dass auch erst, wenn bereits ein Fenster angezeigt wird, von daher 
sollte QT komplett initialisiert und arbeitsfähig sein.

Trotzdem funktioniert der Code nicht...

Um sicher zu gehen, dass die Funktionen wirklich aufgerufen werden, hab 
ich testweise folgenden Code in main eingefügt:
1
[...]
2
3
int main(int argc, char *argv[])
4
{
5
    QApplication a(argc, argv);
6
7
    settings::getSavingLoginData();
8
    settings::setSavingLoginData(true);
9
10
[...]

funktioniert aber auch nicht...

von Karl H. (kbuchegg)


Lesenswert?

Julian W. schrieb:

> void settings::setSavingLoginData(bool toStorage)
> {
>     access->beginGroup("general");
>     access->value("savelogin", toStorage);

setValue

von Julian W. (julian-w) Benutzerseite


Lesenswert?

*kopf*tisch*kopf*tisch*

Danke für den rettenden Hinweis... :)

Ich glaub ich geh jetzt besser schlafen^^

von Rolf Magnus (Gast)


Lesenswert?

Julian W. schrieb:

>> Wenn in deiner Klasse sowieso alles static ist, wozu dann überhaupt eine
>> Klasse?
>
> Nunja, der Übersichtlichkeit wegen halt ;)
> So kann ich über "settings::blablabla" auf alles schön über die
> Autovervollständigung zugreifen.

Dazu bietet sich ein Namespace an.
Solche Pseudo-Klassen sind eher in Java üblich, weil dort Funktionen 
zwangsweise immer in Klassen sein müssen.

von Klaus W. (mfgkw)


Lesenswert?

Das kann in C++ auch Sinn machen.

Spätestens sobald in der statischen Klasse neben reinen Daten auch
zugehörige Methoden nützlich werden, wie z.B. Initialisierung,
Persistenz oder was auch immer.

von Rolf Magnus (Gast)


Lesenswert?

Klaus Wachtler schrieb:
> Das kann in C++ auch Sinn machen.

Eine Klasse, bei der alles static ist, ist in meinen Augen immer 
unsinnig. Sie wird weder jemals instanziiert, noch bringt es was, davon 
abzuleiten, und damit fehlt alles, was eine Klasse im Sinne von 
Objektorientierung ausmacht.

> Spätestens sobald in der statischen Klasse neben reinen Daten auch
> zugehörige Methoden nützlich werden, wie z.B. Initialisierung,
> Persistenz oder was auch immer.

Ich weiß nicht genau, was du damit meinst.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.