webForumDet fria alternativet

Klasser

14 svar · 665 visningar · startad av LilleSkutt

LilleSkuttMedlem sedan feb. 2001265 inlägg
#1

Hallå!

Jag har precis börjat med C++, och har nu lite problem med att skapa och använda klasser...

Varför funkar inte följande?

--------
::::: Tmp.h
--------
#ifndef TMP_H
#define TMP_H

class TmpKlass {
     private:
          char name[25];
          int age;
          void addAge();
     public:
          int getAge();
          void setAge(int newage);
          const char * getName();
          void setName(char newname[25]);
};

#endif
--------
::::: Tmp.cpp
--------
#include <iostream>
using namespace std;
#include "Tmp.h"

void TmpKlass::addAge() {
     age++;
}

int TmpKlass::getAge() {
     return age;
}

void TmpKlass::setAge(int newage) {
     age = newage;
}

const char * TmpKlass::getName() {
     return name;
}

void TmpKlass::setName(char newname[25]) {
     name = newname;
}

Jag får följande felmeddelanden:
Declaration syntax error (Tmp.h: class TmpKlass)

Lvalue required in function TmpKlass::setName(char *) (Tmp.cpp: name = newname)

Parameter 'newname' is never used in function TmpKlass::setName(char *) (Tmp.cpp: } efter name = newname)

Någon som har lust att förklara vad som är fel, och hur man eg. använder arrayer av chars som parametrar och deklarationstyper i klasser? :q

------------------
---
/* LilleSkutt */

[Redigerat av LilleSkutt den 01 sep 2001]

UlfTMedlem sedan maj 20018 027 inlägg
#2

När du sätter egenskapen name, gör inte så som du gjort. Använd strcpy() istället.
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">strcpy(name, newname);
Ett problem med ditt sätt att tilldela name är att name blir satt att peka på precis samma minnesblock som newname. Det är förstås ett stort problem om du sedan gör något med newname på ett annat ställe i klassen. Då ändras också name hur privat den variabeln än är. Det är inte snyggt ur någon OO-synpunkt. Med strcpy() kommer name att fortsätta peka på samma ställe som tidigare. Den funktionen går till minnesblocket som newname pekar på, och kopierar innehållet i det blocket till det block som name pekar på.

Vill du göra det ännu säkrare använder du strncpy.
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">strncpy(name, newname, 25);
Skillnaden är att strcpy kopierar ända tills ett NULL-tecken träffas på, och det är ju inte 100% garanti för att det gör det. strncpy stannar efter n st tecken, i mitt exempel 25 tecken. Observera att NULL-tecken kommer INTE av automatik fästas vid strängslutet. Finns det med i källsträngen kommer det naturligtvis med i målsträngen förutsatt att det är inom n tecken.

LilleSkuttMedlem sedan feb. 2001265 inlägg
#3

Ok! Toppentack för ditt svar :)

Skulle du bara kunna informera mig om hur arrayer av chars används också? Som jag har förstått är de pekare, och när man ska returnera från en funktion måste man använda const char *...? Varför const? :q

Jag förstår inte riktigt sånt här, eftersom att jag inte kan relatera pekare till Java, som jag arbetat med tidigare.

------------------
---
/* LilleSkutt */

developerMedlem sedan aug. 2001458 inlägg
#4

Ett förslag är att använda STL, och den strängklass som finns där. Inkludera <string> om du använder MSVC. Ett bra sätt att undvika fel, och få lättare och felfriare kod.
Sök på google efter STL, eller titta i MSDN - det finns mycket bra info att tillgå.

Varför har du ålder som en integer? Bygg bort risken att för negativ ålder genom att använda en unsigned variabletyp av lämplig storlek. I det här fallet kanske det inte är så allvarligt, men i större system ser man ofta småsaker som leder till buggar. Därför är det bra att redan från början tänka på sådana saker.

På din fråga om const... Antag att du har en klass som har en buffer "char Name[100];" Om du har en metod som returnerar en icke-const pekare till den, så kan man utifrån ändra på det som klassen innehåller. Poängen är ju att alltid gå via klassens SetName/GetName.

<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">#include <string>
using std::string;

class CPerson
{
private:
string Name;
unsigned Age;

public:
CPerson(const string &name, unsigned age) :
Name(name),
Age(age)
{
};

void SetName(const string &name) { Name = name; };
void SetAge(unsigned age) { Age = age; };

const std::string &GetName() { return Name; };
int GetAge() { return Age; };

};

[Redigerat av developer den 02 sep 2001]

LilleSkuttMedlem sedan feb. 2001265 inlägg
#5

Ok, det blev inte mycket klarare, men jag försöker förstå vad du menar developer :)
Vad gör unsigned eg.?

Varför får jag declaration syntax error när jag försöker skapa klasser i mina header-filer? :q
Headerfil - Tmp.h
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">
#ifndef TMP_H
#define TMP_H

class TmpKlass {
...

Och det här, vad är det jag har gjort fel: 'TmpKlass' is not a member of 'TmpKlass' in function TmpKlass::TmpKlass()

Definitionsfil - Tmp.cpp
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">
...
#include "Tmp.h"

TmpKlass::TmpKlass() {
...

Det är alltså konstruktorn som jag får felmeddelande på. Den är definierad i min header-fil. Jag har två st. konstruktorer, en som tar emot attribut och en som inte gör det. Kan det vara problemet?

------------------
---
/* LilleSkutt */

developerMedlem sedan aug. 2001458 inlägg
#6

En unsigned variable kan inte vara negativ. Exempelvis 'short' är 2 Bytes stor för MSVC och kan vara i intervallet –32768 till 32767. Om du istället anger 'unsigned short' är den fortfarande 2 Bytes, men kan nu vara mellan 0-65535.
Om du har nåt som aldrig kan vara negativt, typiskt ålder eller antal, finns det ingen anledning tillåta negativa värden - använd därför unsigned framför variabltypen i sådana fall.

"Den är definierad i min header-fil" - Hurdå? Du skriver att du har 2 överlagrade implementationer. Är båda dessa deklarerade i headerfilen? Felmeddelandet från kompilatorn tyder på att så inte är fallet.

LilleSkuttMedlem sedan feb. 2001265 inlägg
#7

Ok, här kommer min header-fil:
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">
#ifndef TMP_H
#define TMP_H

class TmpKlass {
    private:
        char name[25];
        unsigned int age;
    public:
        TmpKlass();
        TmpKlass(char* inputName, int inputAge);
        int getAge();
        osv...
}

Min definitions-fil:
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">
#include <iostream>
using namespace std;
#include "Tmp.h"

TmpKlass::TmpKlass() {
    TmpKlass("Odefinierat", 1);
}

TmpKlass::TmpKlass(char* inputName, int inputAge) {
    strncpy(name, inputname, 25);
    age = inputAge;
}

int TmpKlass::getAge() {
    return age;
}

osv...

Det är väl inget fel där? :q
Som sagt, är ju ny på det här med C++... Jag är tacksam för försöken att hjälpa mig :e

------------------
---
/* LilleSkutt */

UlfTMedlem sedan maj 20018 027 inlägg
#8

Exakt vad felet består i är jag osäker på eftersom jag aldrig har kodat på ett liknande sätt som du gör i ditt exempel. I vilket fall som helst är det helt onödigt att göra som du gör. Gör på följande vis istället:
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">TmpKlass::TmpKlass() {
strncpy(name, "Odefinierat", 25);
age = 1;
}Du kommer ju faktiskt åt egenskaperna direkt från konstruktorn så du behöver inte krångla till det med metodanrop inne i klassen.

[Redigerat av UlfT den 04 sep 2001]

LilleSkuttMedlem sedan feb. 2001265 inlägg
#9

Ok, det hade löst sig nu... Vet faktiskt inte vad som var fel!

Hur som helst får jag felmeddelande på raden med class TmpKlass {, declaration syntax error, i min header-fil! Gha...

Börjar tröttna på C++, ska nog hålla mig till min Java :l

------------------
---
/* LilleSkutt */

[Redigerat av LilleSkutt den 04 sep 2001]

UlfTMedlem sedan maj 20018 027 inlägg
#10

I header-filen, efter klassens avslutande måsvingeparentes, lägg till ett semikolon. Det är ett av de ställen där man ska ha semikolon efter måsvingeparentesen.

LilleSkuttMedlem sedan feb. 2001265 inlägg
#11

Ok, det funkade inte heller... Med risk för ett alltför långt inlägg; här kommer all kod som strular...

kap12.h

#ifndef KAP12_H
#define KAP12_H

/* Klassen monster, som har hand om alla monster */
class Monster {;
	private: /* Privata variabler, namn, fulhet, färg och värde för elakhet */
		char* monsterNamn;
		int monsterElakhet;
		int* monsterElakhetP; /* Jag använder mig av pekare för värdet */
		int monsterFulhet;
		int* monsterFulhetP; /* Jag använder mig av pekare för värdet */
		char* monsterColor;
	public: /* Globala funktioner */
		Monster(); /* Konstruktor */
		Monster(char* mNamn, int mElakhet, int mFulhet, char* mColor); /* Konstruktor */
		void setNamn(char* mNamn); /* Sätt namn */
		const char* getNamn(); /* Hämta namn */
		void setElakhet(int mElakhet); /* Sätt värde för elakhet */
		int getElakhet(); /* Hämta värde för elakhet */
		void setFulhet(int mFulhet); /* Sätt värde för fulhet */
		int getFulhet(); /* Hämta värde för fulhet */
		void setColor(char* mColor); /* Sätt färg */
		const char* getColor(); /* Hämta färg */
};

#endif

kap12.cpp

#include <iostream>
using namespace std;
#include <cstring>
#include "kap12.h"

/* Konstruktor som inte tar emot attribut */
Monster::Monster() {
	/* Kalla på konstruktorn som tar emot attribut, med angivna standardvärden */
	Monster::Monster("Odefinierat", 5, 5, "Grön");
}

/* Konstruktor som tar emot attribut */
Monster::Monster(char* mNamn, int mElakhet, int mFulhet, char* mColor) {
	monsterElakhet = mElakhet; /* Lägg in det angivna elakhets-värdet */
	monsterElakhetP = &monsterElakhet; /* Lägg in andressen i pekaren */
	
	monsterFulhet = mFulhet; /* Lägg in det angivna fulhets-värdet */
	monsterFulhetP = &monsterFulhet; /* Lägg in adressen i pekaren */
	
	strcpy(monsterNamn, mNamn); /* Lägg in det angivna namnet */
	strcpy(monsterColor, mColor); /* Lägg in den angivna färgen */
}

/* Funktion för att ändra namn på monster */
void Monster::setNamn(char* mNamn) {
	strcpy(monsterNamn, mNamn); /* Lägg in det nya namnet */
}

/* Funktion för att hämta namn */
const char* Monster::getNamn() {
	return monsterNamn; /* Returnera det aktuella monstrets namn */
}

/* Funktion för att sätta värde för elakhet */
void Monster::setElakhet(int mElakhet) {
	*monsterElakhetP = mElakhet; /* Lägg in det nya värdet i pekaren */
}

/* Funktion för att hämta värde för elakhet */
int Monster::getElakhet() {
	return *monsterElakhetP; /* Returnera det aktuella monstrets värde */
}

/* Funktion för att sätta värde för fulhet */
void Monster::setFulhet(int mFulhet) {
	*monsterFulhetP = mFulhet; /* Lägg in det nya värdet i pekaren */
}

/* Funktion för att hämta värde för fulhet */
int Monster::getFulhet() {
	return *monsterFulhetP; /* Returnera det aktuella monstrets värde */
}

/* Funktion för att ändra färg på monster */
void Monster::setColor(char* mColor) {
	strcpy(monsterColor, mColor); /* Lägg in den nya färgen */
}

/* Funktion för att hämta färg */
const char* Monster::getColor() {
	return monsterColor; /* Returnera det aktuella monstrets färg */
}

kap12_uppg1.cpp

#include <iostream>
using namespace std;
#include <cstring>
#include "kap12.h"

const int MONSTER = 3;

void main() {
	/* Skapa en array av monster, varav ett är odefinierat */
	Monster minaMonster[MONSTER] = {
		Monster("Snurre Sprätt", 1, 1, "Grå"), 
		Monster("Dr Alban", 10, 10, "Svart"), 
		Monster()
	};

	/* Iterera igenom alla monster */
	for(int n = 0; n < MONSTER; n++) {
		if(strcmp(minaMonster[n].getNamn(), "Odefinierat") == 0) { /* Kolla om monstret är odefinierat */
			minaMonster[n].setNamn("Honey Monster"); /* I så fall sätt namn, elakhet, fulhet och färg */
			minaMonster[n].setElakhet(5);
			minaMonster[n].setFulhet(5);
			minaMonster[n].setColor("Gul");
		}
	}
	
	/* Iterera igenom alla monster */
	for(int n = (MONSTER - 1); n >= 0; n--) {
		cout << "\n\tMonster:\t" << minaMonster[n].getNamn(); /* Skriv ut namnet på monstret */
		cout << "\n\tElakhet:\t" << minaMonster[n].getElakhet(); /* Skriv ut värde för elakhet */
		cout << "\n\tFulhet:\t" << minaMonster[n].getFulhet(); /* Skriv ut värde för fulhet */
		cout << "\n\tFärg:\t" << minaMonster[n].getColor() << endl; /* Skriv ut färgen på monstret */
	}
}

Kompilationsfel får jag endast på kap12.h, följande felmeddelanden:
Declaration syntax error på class Monster {;

Declaration does not specify a tag or an identifier på raden under class Monster {;

Tack för er hjälp hittills, hoppas bara att ni kan/vill lösa detta också...

------------------
---
/* LilleSkutt */

[Redigerat av LilleSkutt den 06 sep 2001]

developerMedlem sedan aug. 2001458 inlägg
#12

UlfT skriver:

I header-filen, efter klassens avslutande måsvingeparentes, lägg till ett semikolon...

Du har ett semikolon efter klassens inledande måsvinge.

Jag provkompilerade med MSVC, det gick alldeles utmärkt att både kompilera och länka. (Däremot får man access violation) Vilken byggmiljö använder du?

Du har en del buggar, som tyder på att du inte förstår riktigt hur pekare och minneshantering fungerar. Jag tycker du ska läsa igenom och försöka förstå råden jag skrev tidigare.

Exempelvis får du problem om du gör såhär:
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">class C
{
private:
char *m_szName; // onitierad - pekar åt skogen
public:
C(char *szName) { strcpy(m_szName, name) }; // FEL FEL FEL
};

Med char *m_szName deklarerar du bara något som pekar på första tecknet i en "sträng" (det finns inget riktigt sträng-begrepp i C, det är en array av tecken). Den pekar åt skogen initialt.
Det första du gör är att kopiera data till den i din konstruktor, du kopierar alltså en giltig "sträng" en rätt in i skogen. Du har åtminstone 3 alternativ.

1. Ha en array av tecken i klassen, dvs char m_szName[100];.
2. Allokera minne i konstruktorn med malloc() innan du kopierar till strängen och gör free() i destruktorn.
3. Använd en strängklass, vilket är vad jag visade tidigare.

Jag tycker du ska sätta dig in i och förstå vad 1 och 2 är, men välja alternativ 3 eftersom det är så otroligt mycket enklare och ger mindre fel än de 2 första alternativen.

Andra fel är
<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">monsterFulhetP = &monsterFulhet; /* Lägg in adressen i pekaren */
Du lägger här in adressen till funktionsargumentet 'monsterFulhet', vilket du inte har någon som helst nytta av.

Försök göra bryta ner exemplet du gjort och förstå varje del av det. Du försöker göra saker du inte har kunskap om och det GÅR inte. Jag vill med detta absolut inte att vara elak. Tvärtom, jag tror det är steg du behöver. Ta gärna en kurs och/eller läs en tutorial, det finns säkert nån här som kan tipsa om något bra.

Lycka till! :)

[Redigerat av developer den 06 sep 2001]

UlfTMedlem sedan maj 20018 027 inlägg
#13

Developer skrev:

Du har ett semikolon efter klassens inledande måsvinge.

Jag vet inte hur du menar, men jag menar nedanstående:<font size="1" face="Verdana, Arial, Helvetica, sans-serif">Kod:<font size="1" face="Verdana, Arial, Helvetica, sans-serif" color="#666600">class MyClass { // inledande måsvinge
.
.
.
}; // avslutande måsvingeAtt det är där semikolonet ska vara, tror jag vi kan vara överens om. Men om du kallar den måsvingen för inledande, vad kallar du då den första måsvingen?

LilleSkuttMedlem sedan feb. 2001265 inlägg
#14

Ok, jag förstår att du inte vill va elak, jag är tvärtom mycket glad att du är så kritisk som du är!

Ang. semikolonet efter den inledande måsvingen så hade jag inte det där från början... Det var bara nåt jag stoppade dit för att se om det blev bättre, och sedan glömde ta bort... Ett semikolon efter den avslutande måsvingen har jag alltid haft :e

Jag säger det, det är det här med pekare som jag inte hajjar ett jota av :)
Sån skit fanns ju inte i Java :)

Ta gärna en kurs och/eller läs en tutorial, det finns säkert nån här som kan tipsa om något bra.

Jag GÅR faktiskt en kurs... Men jag tycker det går så långsamt, så jag har hoppat framåt på egen hand, och hittills har det funkat bra... Förutom med pekarna då :l ;)

Tro inte att jag kommer sluta med att fråga frågor här i forumet §e :birp Skål!

------------------
---
/* LilleSkutt */

LilleSkuttMedlem sedan feb. 2001265 inlägg
#15

Hallå...

Jag får fortfarande syntaxfel på class Monster {! Jag använder Borlands C++ Builder, och kådar i TextPad (NotePad fast med highlighting)...

Är det någe fel med kompilatorn? :(

------------------
---
/* LilleSkutt */

132 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
130 ms — hämta tråd, inlägg och bilagor (db)