Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Einige C++ Fragen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
07.10.2005, 02:35 Uhr
Pablo
Supertux
(Operator)


Ich hab mir endlich das Ziel gesetzt, ein bisschen C++ zu lernen und bastle grad mit templates, wo ich sagen muss, dass ich (wo ich jetzt verstehe, was templates machen), dass ich von den templates begeistert bin.

Ich hab aber noch ein Paar Fragen:

1.

Ich hab folgendes:


C++:
#include <vector>

template<typename T>
class bild
{
        private:
                std::vector<T> pixels;
                int x_size, y_size; // important for resizing
        public:
                bild(); /* size 16x16 */
                bild(int x_size, int y_size);
                T &getPixel(int pos); // get pixel from 1D position
                void resize(int x_size, int y_size);
                void printImage();
};
...
template<typename T> void bild<T>::printImage()
{      
        int pos = 0;

        for(std::vector<T>::iterator pix = this->pixels.begin(); pix != this->pixels.end(); ++pix) ...



so bekomme ich folgende Warnungen (g++ 3.3.6):

Code:
bild.hh: In member function `void bild<T>::printImage()':
bild.hh:56: warning: `std::vector<T, std::allocator<_CharT> >::iterator' is
   implicitly a typename
bild.hh:56: warning: implicit typename is deprecated, please see the
   documentation for details



Wenn ich typename hinzufüge

C++:
for(typename std::vector<T>::iterator pix = this->pixels.begin(); ...



dann verschwinden die Warnungen. Wieso? Das verstehe ich nicht, warum da von implizite typenames geredet wird. Worauf bezieht sich das typename in der for Schleife? ihmo. wäre es schon klar, dass T ein typename ist, da ich davor template<typename T> habe, oder wie soll ich das verstehen?

2.
Bei C wäre es eigentlich egal, ob ich (wie z.b. in der obigen for Schleife) ++pix oder pix++ hätte, doch ich habe hier mehrmals gelesen, dass bei C++ (besonders mit iteratoren oder so) die Stelle des "++" wichtig wäre, an dieser Stelle müsste eigentlich ++pix stehen und nicht pix++, wieso? Oder spielt das nur ein Rolle, wenn der Operator++ überladen wird?

3.
was macht die "Spezialisierung"? Ich meine (das habe ich gelesen), wenn ich hab

C++:
//allgemeine Version
template<typename T, int size>
void MyVector::multWith(double a)
{
    for(int i=0;i<size;i++)
    {
        data[i]*=a;
    }
}



Das wäre ein skalare Multiplikation für MyVector, sie läuft ganz gut, hat aber eine for-schleife. Dann kann ich auch sowas machen:


C++:
template<>
void MyVector<float,3>::multWith(double a)
{
    data[0]*=a;
    data[1]*=a;
    data[2]*=a;
}


was schneller und ohne Schleife laufen soll. Wieso? was sind die Vorteile da? Was ist, wenn ist 1000 statt 3 habe? Dann wäre eine Mordarbeit alle data[1...999] zu schreiben. Oder hab ich da was falsch verstanden?


4.
Sind Iteratoren, wie std::vector<int>::iterator wirklich nur ein Pointer auf ein Element von vector?

5.
Vererben die abgeleiteten Klassen auch die Konstruktoren, oder muss man neue schreiben, immer wenn man eine Klasse ableitet?

So, das wars im Moment

danke
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!

Dieser Post wurde am 07.10.2005 um 02:44 Uhr von Pablo editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
07.10.2005, 08:48 Uhr
virtual
Sexiest Bit alive
(Operator)



Zitat von Pablo:

1.
Ich hab folgendes:


C++:
...
        for(std::vector<T>::iterator pix = this->pixels.begin(); pix != this->pixels.end(); ++pix) ...



so bekomme ich folgende Warnungen (g++ 3.3.6):

Code:
bild.hh: In member function `void bild<T>::printImage()':
bild.hh:56: warning: `std::vector<T, std::allocator<_CharT> >::iterator' is
   implicitly a typename
bild.hh:56: warning: implicit typename is deprecated, please see the
   documentation for details



Wenn ich typename hinzufüge

C++:
for(typename std::vector<T>::iterator pix = this->pixels.begin(); ...



dann verschwinden die Warnungen. Wieso? Das verstehe ich nicht, warum da von implizite typenames geredet wird. Worauf bezieht sich das typename in der for Schleife? ihmo. wäre es schon klar, dass T ein typename ist, da ich davor template<typename T> habe, oder wie soll ich das verstehen?


Genauer gesagt geht es um den template lokalen Typen iterator: " std::vector<T>::iterator"
ist ja ein Typ und das typename davor wird (neuerdings) vom Standard gefordert um den Compiler darin zu unterstützen, daß er leicht erkennt, daß es ein Typname ist. Es sind mit Templates konstruktionen denkbar, wo der Compiler dies nicht erkennen kann, deshalb gilt in C++ die Regel, daß wenn man außerhalb eines Templates einen Typen referenziert, welche lokal zum Templat definiert wurde, mit typename "hervorheben" muß.


Zitat von Pablo:

2.
Bei C wäre es eigentlich egal, ob ich (wie z.b. in der obigen for Schleife) ++pix oder pix++ hätte, doch ich habe hier mehrmals gelesen, dass bei C++ (besonders mit iteratoren oder so) die Stelle des "++" wichtig wäre, an dieser Stelle müsste eigentlich ++pix stehen und nicht pix++, wieso? Oder spielt das nur ein Rolle, wenn der Operator++ überladen wird?


Ja, im Prinzip spielt es nur dann eine Rolle, wenn op++ überschrieben ist. Aber die deutlich schwerer beantwortbare Frage ist: weisst Du es denn immer, ob op++ überschrieben wurde?
Ich persönlich ziehe ++i generelle dem i++ vor (wenn ich die Wahl habe natürlich), weil man bei ++i eigentlich immer auf der richtigen Seite ist. Vgl. FAQ.


Zitat:

3.
was macht die "Spezialisierung"? Ich meine (das habe ich gelesen), wenn ich hab

C++:
//allgemeine Version
template<typename T, int size>
void MyVector::multWith(double a)
{
    for(int i=0;i<size;i++)
    {
        data[i]*=a;
    }
}



Das wäre ein skalare Multiplikation für MyVector, sie läuft ganz gut, hat aber eine for-schleife. Dann kann ich auch sowas machen:


C++:
template<>
void MyVector<float,3>::multWith(double a)
{
    data[0]*=a;
    data[1]*=a;
    data[2]*=a;
}


was schneller und ohne Schleife laufen soll. Wieso? was sind die Vorteile da? Was ist, wenn ist 1000 statt 3 habe? Dann wäre eine Mordarbeit alle data[1...999] zu schreiben. Oder hab ich da was falsch verstanden?



Spezialisierung kann man aus verschiedenen Gründen machen. Ein Grund kann sein, daß man für einen Datentypen eine schnellere implementierung finden kann, ein anderer, daß man für ein (geringfüfig) anderes Verhalten erzwingen möchte.
Bei obigen Beispiel will der Auto möglicherweise den zusätzlichen Overhead, den die Schleife mit sich bringt umgehen und geht bei kleinen Werten für den Templateparameter size (hier 3) hin und schreibst explizit hin... In 99% der Fälle würde ich solche Spezialisierungen ablehnen, weil so ein Loopunrolling ohnehin oft schon vom Optimierer gemacht wird.
Ein anderes Beispiel wäre zB:

C++:
template<typename T>
bool is_equal_to(const T& a, const T& b) {
      return a==b;
}


Dieses Template geht halt hin und vergleicht zwei Werte, ob sie gleich sind. Okay, soweit klar. Nun macht man aber bei Fließkommazahlen oft die Erfahrung, daß manche Zahlen gleicher sind als andere. Hier würde man vielleicht schreiben:

C++:
template<>
bool is_equal_to(const double& a, const double& b) {
      return std::fabs(a-b)<=2*std::numeric_limits<double>::epsilon();
}


Um den Rundungsproblemen aus den Weg zu gehen.


Zitat:

4.
Sind Iteratoren, wie std::vector<int>::iterator wirklich nur ein Pointer auf ein Element von vector?


Ein Klares nein: bei std::map, std::list usw hast Du in der Regel kompliziertere Vectoren, auch vector Iteratoren müssen nicht zwingend einfach nur ein Zeiger sein.


Zitat:

5.
Vererben die abgeleiteten Klassen auch die Konstruktoren, oder muss man neue schreiben, immer wenn man eine Klasse ableitet?


Man muß neue schreiben, Ausnahmen sind der Defaultconstructor und der Copyconstructor.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
07.10.2005, 21:21 Uhr
Spacelord
Hoffnungsloser Fall


Hi,
zum Thema template Spezialisierung ist vielleicht dieser Artikel noch interessant:
www.gotw.ca/publications/mill17.htm
Im Grunde wird da aufgezeigt dass sich template Spezialisierungen teilweise etwas unnatürlich verhalten können.
Selbst wenn du eine exakt passende template Spezialisierung hast ist trotzdem nicht garantiert dass diese auch genutzt wird.Das tückische ist dass du das eventuell niemals merkst weil es ja keinen Fehler gibt und eine "Standard"-Version,auf Basis des passendsten base templates,generiert wird.

MfG Spacelord
--
.....Ich mach jetzt nämlich mein Jodeldiplom.Dann hab ich endlich was Eigenes.

Dieser Post wurde am 07.10.2005 um 21:22 Uhr von Spacelord editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
08.10.2005, 01:52 Uhr
Pablo
Supertux
(Operator)


Danke für die Erklärungen. Das mit der Spezialisierung habe ich jetzt verstanden, nachdem ich mir dieses equal Bsp von virtual nochmal angeschaut habe.

Wenn man ++ überlädt, wieso ist es ein Unterschied, wenn man ++var oder var++ macht?
--
A! Elbereth Gilthoniel!
silivren penna míriel
o menel aglar elenath,
Gilthoniel, A! Elbereth!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
08.10.2005, 09:02 Uhr
Tommix




Zitat von Pablo:

Wenn man ++ überlädt, wieso ist es ein Unterschied, wenn man ++var oder var++ macht?

'Morgen,

C++:
alt = wert;
wert += 1;
return alt;


ist zumeist länger / langsamer als

C++:
wert += 1;
return wert;



Gruß, Tommix
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
08.10.2005, 09:30 Uhr
(un)wissender
Niveauwart


Man kann operator++ und operator++(int) überladen.

Diese Beispiel das verdeutlichen:


C++:
#include <iostream>

class test
{
public:
    test(int i) : val(i) {}
    
    const test operator++(int)
    {
        std::cout << "postfix\n";
        test old(*this);
        operator++();
        return old;
    }
    
    test& operator++()
    {
        std::cout << "prefix\n";
        ++val;
        return *this;
    }
    
    int getVal() const
    {
        return val;
    }    
    
private:
    int val;    
};
    
int main()
{
    test t(1);
    std::cout << "val ist: " << t.getVal() << '\n';
    std::cout << "val ist: " << (++t).getVal() << '\n';
    std::cout << "val ist: " << (t++).getVal() << '\n';
    std::cout << "val ist: " << t.getVal() << '\n';
}


--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
08.10.2005, 10:01 Uhr
(un)wissender
Niveauwart


Hier kannst du auch noch was nachlesen: operator++
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: