Gå til innhold

Bone's Offisielle C++ hjelpetråd


Anbefalte innlegg

Videoannonse
Annonse

Jeg har skrevet en funksjon som skal redusere en brøk ved å finne høyeste felles divisor. Problemet er at programmet avbrytes av en "floating point exception".

 

Her er koden:

 

int Fraction::reduce(int& num, int& den){
   int b = den;
   int a = num;
   int temp;
   if (a > b){
       temp = a;
       a = b;
       b = temp; //b (bigger) er størst
   }
   temp = 1;
   while (temp != 0){
       cout << "TEMP: " << temp << endl;
       temp = b%a;
       if (temp != 0){
           b = a;
           a = temp;
           //cout << "Breaking off loop.." << endl;
           //break;
       }
   }
   int gcd = temp;
   num = (num/gcd);
   den = (den/gcd);
   cout << "GCD: " << gcd << ", NUM: " << num << ", DEN: " << den << endl;
   return num, den;
}

 

Jeg har prøvd å skrive ut noen variabler i bånn av funksjonen, men den avbryter før det.

Lenke til kommentar

Jeg gjorde det til en øving en gang, da så det slik ut:

 

for GCD:

   long a = this->numerator;
   long b = this->denominator;
   long t;
   while(b != 0){
       t = b;
       b = a%b;
       a = t;
   }
   return a;

For forenklingen:

   int g = gcd();
   this->numerator = this->numerator/g;
   this->denominator = this->denominator/g;

 

Ser ikke floating point exception helt umiddelbart, men det så noe enklere ut. :)

 

Du trenger heller ikke sjekke om a eller b er størst ettersom euclid's algorithm korrigerer dette ved første kjøring uansett.

Endret av Lycantrophe
Lenke til kommentar

Kan i grunn se bort ifra den, det var mest for å lære meg det selv. this brukes når du må eksplisitt vise til at det er medlemsvariabelen i den aktuelle klassen. Nytten kommer når du har to variabler med samme navn der den ene har scope i metoden, den andre i klassen.

Lenke til kommentar

Hei. Jeg støtte på noe som jeg synes er litt rart.

 

Jeg har drevet med litt overlagringer av ++ og -- operatorene, både som medlem av, friend av og utenfor klassen PrimeNumber. Koden over er overlagringene som er utenfor klassen, men både med friend og disse utenfor så er deklareringene mine forskjellige fra definisjonene. Det fungerer likevel som det skal. Er det noen som kan forklare meg hvorfor dette fungerer?

 

Jeg har heller ikke helt skjønt syntaksen til deklareringene med alle "constene". Og når lønner det seg å bruke friend, medlem eller utenfor når det er snakk om overlagringer?

 

Her er litt av koden.

 

class PrimeNumber{
   public:
       PrimeNumber(): number(1){};
       PrimeNumber(int newNumber);
       /*PrimeNumber operator ++(); //Prefix, call-by-reference
       PrimeNumber operator ++(int); //Postfix med int-markør, call-by-value
       PrimeNumber operator --();
       PrimeNumber operator --(int);*/
       void setNumber(int newNumber);
       int getNumber();
       void findNext(); //int eller void?
       void findLast();
       void output();
       /*friend const PrimeNumber operator ++(const PrimeNumber& p1);
       friend const PrimeNumber operator ++(const PrimeNumber& p1, int);
       friend const PrimeNumber operator --(const PrimeNumber& p1);
       friend const PrimeNumber operator --(const PrimeNumber& p1, int);*/
   private:
       bool testNumber();
       int number;
};

const PrimeNumber operator ++(const PrimeNumber& p1);
const PrimeNumber operator ++(const PrimeNumber& p1, int);
const PrimeNumber operator --(const PrimeNumber& p1);
const PrimeNumber operator --(const PrimeNumber& p1, int);

const PrimeNumber operator ++(PrimeNumber& p1){
   p1.findNext();
   return p1;
}

const PrimeNumber operator ++(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findNext();
   return temp;
}

const PrimeNumber operator --(PrimeNumber& p1){
   p1.findLast();
   return p1;
}

const PrimeNumber operator --(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findLast();
   return temp;
}

Lenke til kommentar

Det stemmer, men det er jo det jeg har gjort? I medlemsoverlagringene har jeg ingen argumenter, men på overlagringen utenfor må jeg jo ha et argument da den ikke har tilgang til klassen i seg selv.

 

Jeg får også feilmelding når jeg prøver og kompilere med friend-overlagringene hvis jeg ikke har input, selv om den egentlig skal ha tilgang til de private variablene?

Lenke til kommentar

Jeg legger ved resten koden.

 

 

#include <iostream>
#include <cstdlib>
#include <cmath>

using namespace std;

class PrimeNumber{
   public:
       PrimeNumber(): number(1){};
       PrimeNumber(int newNumber);
       /*PrimeNumber operator ++(); //Prefix, call-by-reference
       PrimeNumber operator ++(int); //Postfix med int-markør, call-by-value
       PrimeNumber operator --();
       PrimeNumber operator --(int);*/
       void setNumber(int newNumber);
       int getNumber();
       void findNext(); //int eller void?
       void findLast();
       void output();
       friend const PrimeNumber operator ++(/*const PrimeNumber& p1*/); //Prøvde uten argumenter, men det fungerer ikke
       friend const PrimeNumber operator ++(const PrimeNumber& p1, int);
       friend const PrimeNumber operator --(const PrimeNumber& p1);
       friend const PrimeNumber operator --(const PrimeNumber& p1, int);
   private:
       bool testNumber();
       int number;
};

/*const PrimeNumber operator ++(PrimeNumber& p1);
const PrimeNumber operator ++(PrimeNumber& p1, int);
const PrimeNumber operator --(PrimeNumber& p1);
const PrimeNumber operator --(PrimeNumber& p1, int);

const PrimeNumber operator ++(PrimeNumber& p1){
   p1.findNext();
   return p1;
}

const PrimeNumber operator ++(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findNext();
   return temp;
}

const PrimeNumber operator --(PrimeNumber& p1){
   p1.findLast();
   return p1;
}

const PrimeNumber operator --(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findLast();
   return temp;
}*/

const PrimeNumber operator ++(){
   number.findNext();
   return p1;
}

const PrimeNumber operator ++(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findNext();
   return temp;
}

const PrimeNumber operator --(PrimeNumber& p1){
   p1.findLast();
   return p1;
}

const PrimeNumber operator --(PrimeNumber& p1, int){
   PrimeNumber temp = p1;
   p1.findLast();
   return temp;
}

/*PrimeNumber PrimeNumber::operator ++(){
   findNext();
   return number;
}

PrimeNumber PrimeNumber::operator ++(int){
   int temp = number;
   findNext();
   return temp;
}

PrimeNumber PrimeNumber::operator --(){
   findLast();
   return number;
}

PrimeNumber PrimeNumber::operator --(int){
   int temp = number;
   findLast();
   return temp;
}*/

PrimeNumber::PrimeNumber(int newNumber){
   number = newNumber;
   if (!testNumber()){
       //Hvordan gjøre dette mer elegant?
       cout << "Not a prime number.. Shutting down.." << endl;
       exit(1);
   }
}

int main(){
   PrimeNumber p1(11);
   p1++;
   p1.output();
   for (int i=0; i<50; i++){
       ++p1;
   }
   p1.output();
   p1--;
   p1.output();
   --p1;
   p1.output();
   return 0;
}

void PrimeNumber::output(){
   cout << number << endl;
}

int PrimeNumber::getNumber(){
   return number;
}

void PrimeNumber::setNumber(int newNumber){
   number = newNumber;
   if (!testNumber()){
       cout << "Not a prime number. Shutting down.." << endl;
       exit(1);
   }
}

bool PrimeNumber::testNumber(){
   int j=0;
   for (int i=2; i<=sqrt(number); i++){
       if (number%i == 0){
           j++;
           if (j>0){
               return false;
           }
           //return true; Problemet her er at 16 vil bli returnert som et primtall fordi 16%3 != 0,
           //og funksjonen returnerer da true ved første tilfellet.
       }
   }
   return true;
}

void PrimeNumber::findNext(){
   do{
       number++;
   }while (!testNumber());
   //return number;
}

void PrimeNumber::findLast(){
   do{
       number--;
   }while (!testNumber());
   //return number;
}

 

Endret av haarod
Lenke til kommentar

Her kommer jeg med et problem til. Jeg har lagd en klasse ved navn Student som inneholder et navn (string), antall fag studenten tar (int) og et dynamisk array som inneholder navnet på fagene.

 

Problemet er at jeg ikke kan inpute mer enn fire fag før jeg får segmentation fault (som betyr at det ikke er mer minne?). Jeg legger ved hele koden, men uthever problemområdene.

 

 

#include <cstdlib>
#include <iostream>
#include <string>

using namespace std;

class Student{
   public:
       Student();
       Student(string newName, int newNumClasses);
       Student(const Student& newStudent);
       Student& operator =(const Student& rightSide);
       int getNumClasses() {return numClasses;}
       void setNumClasses(int newNumClasses);
       string getName() {return name;}
       void setName(string newName);
       [b]void input();[/b]
       void newLine();
       void output();
       ~Student();
   private:
       string name;
       int numClasses;
       [b]string *classList;[/b]
};

int main(){
   Student Haakon;
   [b]Haakon.input();[/b] //Kun hvis jeg setter numClasses større enn 4.
   Haakon.output();
   return 0;
}

Student::Student(): name("Ingen T. Ing"), numClasses(4){
   classList = new string[numClasses];
}

Student::Student(string newName, int newNumClasses): name(newName){
   if (newNumClasses >=0){
       numClasses = newNumClasses;
   }
   classList = new string[numClasses];
}

Student::Student(const Student& newStudent): name(newStudent.name), numClasses(newStudent.numClasses){
   classList = new string[numClasses];
   for (int i=0; i<numClasses; i++){
       classList[i] = newStudent.classList[i];
   }
}

[b]void Student::input(){
   cout << "Skriv inn navnet ditt: ";
   getline(cin, name);
   //newLine(); //Overflødig her
   cout << "Du skrev: " << name << endl;
   cout << "\nSkriv inn antall klasser (minst 0): ";
   cin >> numClasses;
   cout << "Du skrev: " << numClasses << endl;
   newLine();
   if (numClasses < 0){
       cout << "Antall klasser kan ikke være negativt. Avslutter.." << endl;
       exit(1);
   }
   string className;
   for (int i=0; i<numClasses; i++){
       cout << "Skriv inn fag:\n";
       getline(cin, className); //prøv med cin >> className etterpå.
       /*if (classList == NULL){
           cout << "Out of memory. Shutting down.." << endl;
           exit(1);
       }*/ //Prøvde og kjøre denne testen, men jeg er ikke helt sikker på syntaks, men jeg skal jobbe mer med den.
       classList[i] = className;
   }
}[/b]

void Student::newLine(){
   string avfall;
   getline(cin, avfall);
}

void Student::output(){
   cout << name << " sine fag: ";
   for (int i=0; i<numClasses; i++){
       cout << classList[i];
       if (i<numClasses-1){
           cout << ", ";
       }
   }
   cout << endl;
}

Student& Student::operator =(const Student& rightSide){
   if (numClasses != rightSide.numClasses){
       delete [] classList;
       classList = new string[rightSide.numClasses];
   }
   numClasses = rightSide.numClasses;
   name = rightSide.name;
   for (int i=0; i<numClasses; i++){
       classList[i] = rightSide.classList[i];
   }
   return *this; //Adressen til det kallende objektet.
}

[b]Student::~Student(){
   delete [] classList;
}[/b]

void Student::setNumClasses(int newNumClasses){
   if (newNumClasses >= 0){
       numClasses = newNumClasses;
   }
   else{
       cout << "Number of classes can't be negative. Shutting down.." << endl;
       exit(1);
   }
}

void Student::setName(string newName){
   name = newName;
}

 

 

Det gikk visst ikke an å ha fet skrift inne i kodeboksen, men problemet ligger i input(), og muligens i destructoren ~Student().

 

EDIT: Jeg fant problemet. Jeg hadde satt default constructoren til å sette av plsas til fire fag, men endret det nå til 50 så da fungerer det fint.

Endret av haarod
Lenke til kommentar

Jeg har drevet med litt overlagringer av ++ og -- operatorene, både som medlem av, friend av og utenfor klassen PrimeNumber.

 

("overlagring"? *grøsss*)

 

La oss se: "A unary operator (...) can be defined by either a nonstatic member function taking no arguments or a nonmember function taking one argument."

 

Noen operatorer er det veldig naturlig å ha utenfor klassen (eksempelvis op+()) for å unngå asymmetrisk oppførsel; mens andre er det kanskje ikke urimelig å definere som medlemmer.

 

Koden over er overlagringene som er utenfor klassen, men både med friend og disse utenfor så er deklareringene mine forskjellige fra definisjonene. Det fungerer likevel som det skal. Er det noen som kan forklare meg hvorfor dette fungerer?

 

Det fungerer ikke som "det skal", for en rimelig definisjon av skal :) Men da må man lage et par eksempler. En veldig grei regel (og spesielt for en klasse som skal opptre som et tall) er å følge semantikken til de innebygde operatorne.

 

Jeg har heller ikke helt skjønt syntaksen til deklareringene med alle "constene". Og når lønner det seg å bruke friend, medlem eller utenfor når det er snakk om overlagringer?

 

Det finnes ingen allmennanvendelig oppskrift, selv om Scott Meyers skriver noe om akkurat dette i "Effective C++".

 

Det kan se ut som at det er litt forvirring på gang: "friend"-deklarasjoner er egentlig ikke en del av avgjørelsen om hvorvidt en funksjon skal være medlem eller ej. Men en kort huskeliste:

 

* Funksjoner som kan tenkes å kunne være virtuelle, må nødvendigvis være medlemmer.

* Noen funksjoner kan ikke være medlemmer, grunnet deres virkemåte (f.eks. op<< og op>> på streams, kommutative binære aritmetiske operatorer, osv.)

* Det spørs opplagt i hvilken grad operatoren trenger tilgang til implementasjonsdetaljene i klassen for å avgjøre om de skal være medlemmer eller ej.

 

class PrimeNumber{
   public:
       PrimeNumber(): number(1){};
       PrimeNumber(int newNumber);
       PrimeNumber operator ++(); //Prefix, call-by-reference
       PrimeNumber operator ++(int); //Postfix med int-markør, call-by-value
       PrimeNumber operator --();
       PrimeNumber operator --(int);

 

Nei.

 

En av hovedreglene (ikke bare ved operator-overloading, men ellers også) er "principle of least surprise". Egne operatorer må av den grunn matche semantikken til måten sammenlignbare innebygde operatorer fungerer.

 

Prefiksoperatorne returnerer en PrimeNumber&. Postfiksoperatorne returnerer en kopi, og derfor en const PrimeNumber&.

 

(forresten, hva betyr "prefix, call-by-reference" her?)

 

const PrimeNumber operator ++(PrimeNumber& p1){
   p1.findNext();
   return p1;
}

 

Dette kan bli en ekkel overraskelse, når du sender resultatet av preinkrement til en funksjon som modifiserer objektet. Returner en referanse til det objektet du modifiserer.

Endret av zotbar1234
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...