Toon posts:

[c++] Protected attributes in derived class.

Pagina: 1
Acties:

Verwijderd

Topicstarter
Klein vraagje welke ik stel in de context van mijn implementatie, met wellicht wat irrelevante info.

Ik heb een template based class ontwikkeld genaamd 'collection' die onder andere een attribute 'count' bezit om aan te geven hoeveel items er in opgeslagen zijn. Deze class is abstract en bevat een virtual method 'insert', die een item toevoegd van een willekeurig type:
C++:
1
2
3
4
5
6
7
8
template <class Data>
class collection
{
protected: 
    int count;
public:
    virtual void insert (Data *data) = 0;
}

Nu maak een derived class 'list' welke aan het abstracte type 'collection' voldoet. Deze list implementeert zijn eigen insert en verhoogt daarin 'count'. Nu kan ik voor 'count' echter enkel 'this->count' gebruiken en niet gewoon 'count'. In veel voorbeelden op internet zie ik dat dit wel zou moeten kunnen:
C++:
1
2
3
4
5
6
7
8
9
10
11
template <class Data>
class list : public list
{
public:
    void insert (Data *data)
    {
       prop_ergens_in_list(data);
       this->count++; // werkt
       count++;       // werkt niet
    }
}

Mijn g++ compiler herkent de hele count niet. Indien ik er 'this->' voor plaats is er niets aan de hand.
code:
1
2
list.cc: In member function `void list<Data>::insert(Data*)':
list.cc:147: error: `count' undeclared (first use this function)
Een van de voorbeelden op http://www.cplusplus.com/doc/tutorial/tut4-3.html doen mij vermoeden dat het ook anders kan.

Heeft iemand enig idee of dit normaal gedrag is en wat het achterliggende idee hierbij is?

  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Dat komt omdat een non-dependent name niet in een dependent base wordt opgezocht.

Sorry ik zei het verwarrend. Ik zal het ook uitleggen...

Stel dat je een dependent base hebt, dus een base class die van een template parameter afhangt.

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
template <typename T>
struct Base {
   int count;
};

template <typename T>
struct Derived : public Base<T> {
   void foo() { count++;} // increment count
};

template <>
struct Base<float> {
   enum {count = 0;} // always empty
};

int main() {
   Derived<float> d;
   d.foo();
}

Wat er nu gebeurt is dat als de compiler de definitie van de derived template class leest (met dependent base, want hangt af van T) dan zal hij 'count' zien als int, als deze opgezocht zou worden. Stel nu dat er later een specialisatie van die base class voorkomt, en die herdefineerd de naam 'count' naar iets anders. Wat dan? count is nu geen int, dus de eerdere binding aan een int klopt helemaal niet. (en dus komt er pas een error op het moment dat je foo() instantieert. Dat kan in andere file zijn!)

Om dit te voorkomen moet je dus zorgen dat de compiler de naam 'count' NIET meteen opzoekt (alleen niet in de dependent base! dus er komt meteen een error) Nou is dit precies het mechanisme voor dependent names (vanwege het kip en het ei probleem in sommige gevallen, kan een compiler een dependent name in een template class nooit opzoeken bij definitie, en dus doet hij dat nooit)

Welnu, hoe hier een dependent name van te maken? Door hem af te laten hangen van T. Dit kan bv door 'this->count' te schrijven, want "this" staat voor template <typename T> class Derived, en hangt af van T. Je kan ook bv doen Base<T>::count, dat hangt ook af van T, en is dus een dependent name. Maar dan moet je uitkijken met virtuele functies, die mechaniek werkt dan niet meer. Het beste is om maar gewoon voor alles "this->xxx" te schrijven als je een dependent base hebt.

offtopic:
woh ik heb een post 124% geedit :P

[ Voor 130% gewijzigd door Zoijar op 16-09-2005 23:00 . Reden: ik slaap nog half ofzo... weer een fout eruit hehe ]


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Prachtig, nog een bug in VC7.1 :)

Ter illustratie:
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <iostream>

int count = 1234;

template <typename T>
struct Container {
    int count;
};

template <typename T>
class List : public Container<T> {
public:
    void increment() {
        count++;
    }
};

int main() {
    List<float> list;
    list.count = 0;
    list.increment();
    std::cout << "Count is " << list.count << std::endl;

    return 0;
}

Deze code hoort dus "Count is 0" te printen. VC7.1 print gewoon "Count is 1", een bug dus. Anyway, dit maakt het punt dus nog duidelijker dan mijn hele verhaal denk ik...

VC2005 doet het ook fout... jammer dat MS bug report site het niet doet bij mij. Dit al de tweede serieuze bug die ik in VC2005 vind binnen een maand ofzo... Denk dat ik maar eens van visual C++ af ga. gcc doet het al tijden gewoon beter.

[ Voor 24% gewijzigd door Zoijar op 16-09-2005 23:17 ]


Verwijderd

Topicstarter
Ik houd er niet van om iets werkends te hebben zonder te weten waarom eigenlijk. Bedankt voor de duidelijk uitleg. Ik kan weer verder :-)

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoijar: is geen bug, staat in de docs dat het dependent names niet support en dat templates gewoon "geparsed" worden op het moment dat ze worden geinstantieerd

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

.oisyn schreef op zaterdag 17 september 2005 @ 00:15:
Zoijar: is geen bug, staat in de docs dat het dependent names niet support en dat templates gewoon "geparsed" worden op het moment dat ze worden geinstantieerd
haha, goed... ja, je kan in je docs gewoon zetten "dit is geen C++ compiler, wij hanteren onze eigen standaard, en daarom zijn onze gebreken dus geen bugs" ... :P

  • .oisyn
  • Registratie: September 2000
  • Nu online

.oisyn

Moderator Devschuur®

Demotivational Speaker

Mja, op die manier zou je het missen van export ook een bug kunnen noemen. Ik vind het een bug als het niet werkt volgens hun eigen specs, maar in de docs staat duidelijk dat het op sommige punten afwijkt van de standaard. Beetje flauw om die dingen 'bugs' te noemen ;)

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Zoijar
  • Registratie: September 2001
  • Niet online

Zoijar

Because he doesn't row...

Als ze op deze manier:
A highly ANSI/ISO C++ -compliant compiler for building modern C++ code. Compile and use popular C++ community-written libraries including LOKI, BLITZ, and BOOST
Advanced language features including Partial Template Specialization and Partial Ordering of Function Templates to create more compact and reusable code

...
In general, Microsoft is committed to implementing the complete ISO C++ standard.
adverteren met hun compiler, dan zie ik afwijkingen van die standaard toch als "bugs". Of in ieder geval als missing features dan. Het gebrek aan 'export' vind ik ook zwak... andere compilers kunnen het wel, andere compilers zijn ook gewoon compliant. En die code zoals boven, volgens de standaard mag je daar "0" verwachten te zien. Op elke compliant compiler is dat ook zo, maar op de MS compiler is dat niet zo. Iemand zit hier dus fout, en mijn code is het niet, dus is het de compiler ;) Je bug documenteren is gewoon flauw. Als ik een routine schrijf om op te tellen, en dan stel dat we proberen om de wiskundige regels op zijn best na te leven, om vervolgens te stellen dat onze optel routine wel 1+1=3 uitrekent, is dat dan geen bug?
Pagina: 1