[visual c++]Probleem namespace & fiend funcions

Pagina: 1
Acties:

  • Rempage0611
  • Registratie: December 2000
  • Laatst online: 23-09-2025

Rempage0611

9405 WP @ 2x SMA Sunny Boy

Topicstarter
Ik ben momenteel een c++ programma aan het omschijven. Eerst stond het programma om een linux machine. Nu moet het naar microsoft visual c++. een probleem wat ik tegen kwam:

Op het moment dat ik "using namespace std" gebruikte kan de friend function geen private members van een classe aan roepen

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <iostream>
#include <string>
using namespace std;

class Test{
private:
   string a;
public:
   test(){
   a = "hallo";
}
   friend ostream& operator<<(ostream & os, const Test & t) ;
};

ostream & operator << (ostream & os, const Test & t) {
        return os<<t.a;
}

int main(){
   Test t;
   cout<<t;
   cin.get();
   return 0;
}


Het gaat er om dat nu de private member niet bereikbaar is in de friend function. WAAROM?
Als je namespace weghaald dan werkt het wel. maar die heb ik nodig voor mijn STL functions.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
edit:
Ok, even m'n hele post omgooien. Wat is het precies dat je wilt doen? Wil je de bestaande operator<< in de std namespace overloaden voor je eigen klasse? Of wil je gewoon een operator<< definiëren in de default namespace?

In het eerste geval zul je expliciet de functie in de std-namespace moeten declareren, die functie ook opgeven als friend functie en vervolgens in de std-namespace moeten implementeren:
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
26
27
28
29
30
31
32
#include <iostream>
#include <string>
using namespace std;

class Test;

namespace std {
  ostream & operator << (ostream & os, const Test & t);
}

class Test{
private:
   string a;
public:
  Test(){
    a = "hallo";
  }
   friend ostream& std::operator<<(ostream & os, const Test & t) ;
};

namespace std {
  ostream & operator << (ostream & os, const Test & t) {
    return os<<t.a;
  }
}

int main() {
   Test t;
   cout<<t;
   cin.get();
   return 0;
}

Ik heb even getest met GCC 3.2.1 en die vindt dat in ieder geval perfect.

Wil je echter los van de std-namespace een eigen functie definiëren, dan zou het goed moeten zijn zoals je het nu doet, maar ik kan me voorstellen dat het fout gaat omdat de compiler denkt dat je aan een overloaded versie van de operator<< uit de std-namespace probeert te refereren. De friend declaratie geldt dus niet voor jouw functie, die in de default namespace zit. Dat probleem is waarschijnlijk te verhelpen door je functie al boven je klassedefinitie te declareren, zodat de compiler wel bindt zoals wenselijk is.

De code wordt dan zo iets:
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
26
27
28
#include <iostream>
#include <string>
using namespace std;

class Test;

ostream & operator << (ostream & os, const Test & t);

class Test{
private:
   string a;
public:
  Test(){
    a = "hallo";
  }
  friend ostream& operator<<(ostream & os, const Test & t) ;
};

ostream & operator << (ostream & os, const Test & t) {
  return os<<t.a;
}

int main() {
   Test t;
   cout<<t;
   cin.get();
   return 0;
}

In hoeverre het door jouw opgemerkte gedrag in overeenstemming is met de C++ standaard zou ik niet precies weten; misschien kan iemand anders daar meer over vertellen. Ik vermoedt dat het niet helemaal klopt, aangezien GCC 3.2.1 die extra declaratie weer niet nodig heeft. In ieder geval zou je probleem zo opgelost moeten kunnen worden.

[ Voor 103% gewijzigd door Soultaker op 12-05-2003 20:17 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 21-08 17:14
Hohoho. std:: is voor de compiler, daar mag je helemaal geen functies in definieren.

De vraag die je hiet moet stellen is of de friend declaratie dezelfde functie declareert als de definitie definieert. Het alternatief is dat de friend declaratie een (ongeimplementeerde) overload declareert van operator<< met andere argumenten. Hoe kunnen de argumenten verschillen? Als de lookup van ostream in de ene scope andere resultaten geeft dan de lookup in een andere scope.

Het is natuurlijk duidelijk dat de lookup van de argumenten van operator<<(ostream & os, const Test & t) ; beinvloedt wordt door de using namespace. Als je duidelijk wil zijn schrijf je daar gewoon std::ostream&. Dat is altijd dezelfde ostream, einde discussie.

Voor de rest van de discussie wordt het belangrijk welke VC++ je hebt.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 22-08 01:56
MSalters schreef op 12 mei 2003 @ 20:22:
Hohoho. std:: is voor de compiler, daar mag je helemaal geen functies in definieren.
Nee hoor, std is gewoon de naam van een namespace en is op geen enkele manier 'speciaal'. Of het netjes is om functies toe te voegen aan de namespace van een andere library is altijd de vraag, maar dat is niet meer of minder het geval bij 'std'.
De vraag die je hiet moet stellen is of de friend declaratie dezelfde functie declareert als de definitie definieert. Het alternatief is dat de friend declaratie een (ongeimplementeerde) overload declareert van operator<< met andere argumenten.
Dat lijkt inderdaad het probleem te zijn.
Het is natuurlijk duidelijk dat de lookup van de argumenten van operator<<(ostream & os, const Test & t) ; beinvloedt wordt door de using namespace. Als je duidelijk wil zijn schrijf je daar gewoon std::ostream&. Dat is altijd dezelfde ostream, einde discussie.
Het gaat niet om de ostream, maar om de operator<<: daar zit de ambiguïteit in. Overigens ben ik van mening (en met je eens) dat het not-done is om in een header file (waar het hier om lijkt te gaan) 'using namespace' te gebruiken, maar in source files wil dit gewoon nog wel eens handig zijn.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 22-08 13:19

.oisyn

Moderator Devschuur®

Demotivational Speaker

Een header file met een int main ()? :D

Overigens compileert je code prima onder zowel comeau als vc++ 7.1. Let er trouwens op dat die functie die op een constructor lijkt geen constructor is: de klassenaam is Test, maar je functie heet test (let op die hoofdletter), en wordt dus ook als functie gezien (zonder return-type weliswaar, wat niet mag volgens de standaard) en niet als constructor

Ik weet niet of het er wat mee te maken heeft, maar als ik me niet vergis had VC6 een niet of half geimplementeerde koenig-lookup, waardoor de operators buiten de std namespace gedefinieerd moeten worden zodat de compiler ze kon vinden.

Een andere work-around, die sowieso door veel mensen als 'mooier' wordt gezien dan friend functies in het algemeen, is een public methode maken in Test die de data naar een ostream schrijft. Vervolgens kun je de << overloaden die die methode aanroept:

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Test
{
private:
    int i;

public:
    std::ostream & write (std::ostream & os)
    {
        return os << i;
    }
};

std::ostream & operator << (std::ostream & os, const Test & t)
{
    return t.write (os);
}

int main ()
{
    Test test;
    std::cout << test << std::endl;
    return 0;
}

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.