Gå til innhold

Problemer med ostream-objekter


Anbefalte innlegg

jeg prøver å lage min egen lille manipulator.

 

Se for deg

cout << bin << 127;

med resultatet: 01111111

 

Problemet er at jeg må lage en klasse som har et ostream objekt som medlem.

Kompilatoren klager på at det ikke er konstruktør eller at jeg ikke har skrevet noe i konstruktøren. (får ikke initialisert ostreamobjektet)

Klassen inneholder kunn dette medlemmet og noen funksjoner.

 

namespace bmanip{

  using std::ostream;

  using std::stringstream;

  using std::INT_MAX;

  class binary_manipulator{

  public:

      binary_manipulator():binaryobject()

      {

      }   

      ostream& operator<< (ostream& o)

      {

          stringstream bufferstrom; bufferstrom << o;

          int i = 0; bufferstrom >> i;

          if(!i)return o;

          for (int p = INT_MAX;p>0;p/=2)

          {

            if (p & i)

            binaryobject << 1;

            else

            binaryobject << 0;

          }   

          return binaryobject;

      }   

  private:

      ostream binaryobject;

  }; 

  binary_manipulator bin;

}

 

Endret emnetittel. Tre-ords-regelen er her for en grunn. PoleCat

Endret av PoleCat
Lenke til kommentar
Videoannonse
Annonse

Trodde man skulle unngå å lage iostream operatorerer som medlemmeri klasser?

Definer den i public scope, med reference til binary_mainpulator som et av argumentene. Deretter legger du til friend ostream& operator<<ostream&(ostream&, binary_manipulator&); i binary_mainpulator klassen

 

(Dette er litt gjetting, men tror det er en bedre løsning)

Lenke til kommentar

Har funnet ut mye av det der ja....

Slik jeg ser det, er løsningen min umulig fordi <<operatoren er venstre-assosiativ (vanskelig ord).

Fikk til det jeg ville, med en liten endring:

cout << (bin << 127);

Dette fungerer. Ostream&-operatoren satt jeg opp slik du skrev.

I tillegg la jeg inn

friend binary__manipulator& operator<< (binary__manipulator&, int&);

 

Dessuten er medlemet ikke lenger en ostream, men en stringstream.

Etter mye trøbling fant jeg og ut at for å lese av en stringstream, må man bruke stringstream::str();

 

header-filen som inneholder bin, ser nå slik ut

#ifndef _BIN_MANIP

#define _BIN_MANIP

 

#ifndef _CPP_SSTREAM

#include <sstream>

#endif

 

#ifndef _CPP_OSTREAM

#include <ostream>

#endif

 

#ifndef _CPP_CLIMITS

#include <climits>

#endif

 

namespace bmanip{

  using std::stringstream;

  using std::ostream;

 

  class binary__manipulator{ 

  friend ostream& operator<< (ostream&, binary__manipulator&);

  friend binary__manipulator& operator<< (binary__manipulator&, int&);

 

  private:

      stringstream binaryobject;

  }; 

 

  binary__manipulator bin;

  ostream& operator<< (ostream& ut, binary__manipulator& b)

  {

      int i = 0; b.binaryobject >> i;

      if(!i)return ut;

      stringstream super;

      for (int p = (INT_MAX/2)+1;p>0;p/=2)

      {

        if (p & i)

        super << 1;

        else

        super << 0;

      }   

      ut << "Binaert: " << super.str();

      return ut;

  }

  binary__manipulator& operator<< (binary__manipulator& b, int& i)

  {

      b.binaryobject << i;

      return b;

  }   

}

#endif

 

Begynner å likne på en biblioteks-stil synes jeg. Jeg er ganske fornøyd med oppsettet. Har liksom aldri brydd meg om å skrive ryddig før.

BTW, ser jeg selv at de include-makroene er litt vel overdrevne.

 

 

Noen forslag til forbedring av filen? Hvis jeg skal lage mine egne header-filer, som jeg kan bruke seinere, hva må forbedres?

Lenke til kommentar

Jeg har ikke fulgt med her, men hva med inlining? Dette er rimelig små kodesnutter, og det kan dermed hende dette er aktuellt.

 

Er ikke sikker på hvor bra koden er, minns jeg ryddet en del opp i den etter posten ble lagt ut, men du skjønner sikkert poenget eller idéen den prøver å få frem:

http://forum.hardware.no/index.php?showtop...dpost&p=2233527

 

(selvfølgelig ikke nødvendig, du kan jo i grunn bare bruke "vanlig" inline)

 

Edit2:

Du trenger ikke include-guardsene du har rundt forbi.

Endret av søppel
Lenke til kommentar

Ser ikke helt viktigheten med å gjøre funksjonene inline.

Ettersom det er en bibliotekfil, vet man jo aldri hvor mange ganger funksjonene skal tas i bruk.

For et lite program gir det kanskje en litt bedre ytelse, men jeg prøver å lage en fil til allslags bruk.

Rett på meg hvis jeg tar feil.

 

Har nå oppgradert det hele litt

Følgende vil nå fungere fint.

cout << "Tallet" << tall << " er " << bin << tall << " binaert";

Operatoren: binary_manipulator& operator<<(ostream&, binary_manipulator&) lagrer en adresse til en ostream (eksempelvis cout) i objektet og returnerer en referanse til objektet.

Dermed har nå objektet ansvaret for alt som kommer inn.

Denne gangen la jeg bin i det globale navnerommet, siden den er det eneste viktige i filen.

(cout << bin) //lagrer &cout og returnerer adressa til bin
(bin << int) //bin lager binærtallet og sender det til cout
(bin << char*) //sender strengen videre til cout

 

//----------------bin:manip.h-----------------
#ifndef _BIN_MANIP
#define _BIN_MANIP

#include <sstream>
#include <ostream>
#include <climits>

namespace bmanip{
 using std::stringstream;
 using std::ostream;
 
 class binary__manipulator{   
 friend binary__manipulator& operator<< (ostream&, binary__manipulator&);
 friend binary__manipulator& operator<< (binary__manipulator&, int&);
 friend binary__manipulator& operator<< (binary__manipulator&, char*);
 
 private:
     stringstream binaryobject;
     ostream* cout_referanse;
 };    
 inline binary__manipulator& operator<< (ostream& ut, binary__manipulator& b)
 {
     b.cout_referanse = &ut;
     return b;
 }
 binary__manipulator& operator<< (binary__manipulator& b, int& i)
 {
     if(!i)return b;
     stringstream super;
     for (int p = (INT_MAX/2)+1;p>0;p/=2)
     {
       if (p & i)
       super << 1;
       else 
       super << 0;
     }    
     *b.cout_referanse << super.str();
     return b;
 }    
 inline binary__manipulator& operator<< (binary__manipulator& b, char* i)
 {
 *b.cout_referanse << i;
 return b;
 }
}

bmanip::binary__manipulator bin;
#endif

Endret av Styggentorsken
Lenke til kommentar
..vet man jo aldri hvor mange ganger funksjonene skal tas i bruk.

Riktig det, men er funksjonene små nok tar koden for kallet like mye (eller neeesten) plass som selve funksjons-koden. U c? Da blir det hipp som happ sånn rom-messig sett, men forskjellen i tid kan variere sterkt siden et kall tar mer tid. Det blir en vurderingssak; opp til deg. (Edit: bruk en disassembler og/eller kjør noen benchmarks -- det er uansett optimaliseringer, så er kanskje ikke så viktig før tilslutt)

 

Kan ta en titt på resten litt ut over dagen .. må få ordna meg noe middag her nå ... :]

(Edit3: Tror jeg droppa det, C++ er for mye rot for meg i dag)

 

Edit2:

Det A_N_K sier under stemmer, men om du gir den noen hint (-O2 eller -O3 ..o.l.) at du virkelig vil optimalisere så er det større sjans for at inline blir overholdt. Dette er det klienten av biblioteket (headeren) som (av)gjør.

Endret av søppel
Lenke til kommentar

Ohh .. btw. - det kan hende jeg er full her, men det å definere et instans av klassen i headeren:

...

bmanip::binary__manipulator bin;

...

..er ingen god idé da flere .cpp-filer kan inkludere headeren; linker-feil!

 

uhm. . mye mulig at jeg surrer her

 

Edit:

For å være helt ærlig ville jeg droppa hele greia og gjordt det veldig enkelt og idiot-sikkert:

#include <iostream>
#include <sstream>
#include <climits>


inline std::string bin(int i)
{
std::stringstream ss;

for(int p = (INT_MAX / 2) + 1; p > 0; p /= 2) {
 if (p & i)
 	ss << 1;
 else
 	ss << 0;
}    
return(ss.str());	
} // bin


using namespace std;


int main()
{
for(unsigned int i = 0; i < 50; i++)
 cout << bin(i) << endl;
return(0);
} // main

 

Det kan hende det er fordi jeg ikke finner noen god nok løsning som fungerer i alle situasjoner, da jeg ikke er nok kjennt med det interne opplegget i io-biblioteket.

Endret av søppel
Lenke til kommentar

tja, tenkte kanskje det kunne være lærerikt

, men da jeg fikk til klassen såpass bra, kan det hende at jeg bruker den littegrann.

 

Gjør ikke include-guardsene at filen ikke inkluderes flere ganger??

 

har sliti mye med io-biblioteket ja, tror nok det finnes bedre løsninger enn denne, men jeg klarer i alle fall å tilfredsstille alle forventningene jeg hadde til klassen når jeg begynnte på den.

 

Hva mangler eventuelt? Jeg tror klassen holder til alt jeg skal bruke den til.

 

BTW, løsningen din er også helt grei. Jeg ville nok brukt den hvis jeg bare måtte lage noe i farta eller hvis ytelse hadde noe å si.

Endret av Styggentorsken
Lenke til kommentar
Gjør ikke include-guardsene at filen ikke inkluderes flere ganger??

 

Jo, men bare pr. kompilering. Når man kompilerer flere filer så inkluderes headeren flere ganger, og du får flere definisjoner av symbolet 'bin'.

 

a.cpp:

#include "bin.hpp"
int main()
{
return(0);
} 

 

b.cpp:

#include "bin.hpp"

 

bin.hpp:

#ifndef _BIN_
#define _BIN_

class Bin {
}; // Bin

Bin bin;

#endif // #ifndef _BIN_

 

g++ a.cpp b.cpp -o prog

/tmp/ccySSKsA.o(.bss+0x0): multiple definition of `bin'

/tmp/ccUVWaTI.o(.bss+0x0): first defined here

collect2: ld returned 1 exit status

 

Definisjonen av symbolet 'bin' må legges i en egen .cpp-fil (bibliotek).

Endret av søppel
Lenke til kommentar

//--------bin_manip.h---------
#ifndef _BIN_MANIP
#define _BIN_MANIP

#include bin_manip.cpp
/*....*/

namespace bin_manip{
/*....................*/
   class binary_manipulator{
   /*...*/
   };
};
#endif

//--------bin_manip.cpp---------
#include bin_manip.h

class bin_manip::binary_manipulator;

bin_manip::binary_manipulator bin;

 

Vil dette fungere?

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...