Hi, vielleicht kann mir jemand helfen:
ich habe ein C-Struktur (BS), die einen C++ Wrapper (B) bekommen soll,
dem eine C-Instanz als Pointer gegeben wird.
Weiterhin gibt es eine Klasse (A), die als Member (unteranderem) die
C-Struktur enthält.
Nach außen soll sie aber den Wrapper als Interface anbieten.
Einmal als const Object und einmal als veränderbares Objekt.
damit man dem const Wrapper nicht einfach kopiert und damit die nicht
const-Routinen aufrufen kann, sind Kopie-C'tor und =-Operator privat, so
dass nur A sie aufrufen kann.
Nun schlägt aber auch die Zuweisung der A.getB() an eine Referenz fehl,
was mir nicht einleuchtet. Ich häte erwartet, dass das geht.
http://codepad.org/YcHXvtjj> error: 'B::B(const B&)' is private
1
structBS{
2
inta;
3
intb;
4
};
5
6
classB
7
{
8
public:
9
B(BS*bs)
10
:m_bs(bs)
11
{}
12
13
intgetA()const{returnm_bs->a;}
14
voidsetA(inta){m_bs->a=a;}
15
16
private:
17
BS*m_bs;
18
19
B(constB&oth){
20
this->m_bs=oth.m_bs;
21
}
22
B&operator=(constB&oth){
23
this->m_bs=oth.m_bs;
24
return*this;
25
}
26
friendclassA;
27
};
28
29
30
31
classA
32
{
33
public:
34
A(inta,intb)
35
{
36
m_bs.a=a;
37
m_bs.b=b;
38
}
39
40
constBgetBconst()
41
{
42
returnB(&(const_cast<A>(this)->m_bs));// rückgabewert const, daher ist erzeugen von Wrapper ok
43
}
44
45
BgetB4change()
46
{
47
returnB(&m_bs);
48
}
49
50
51
private:
52
BSm_bs;
53
};
54
55
intmain()
56
{
57
Aa(10,11);
58
// B b = a.getB(); // schlägt logischer weise fehl
59
// const B& c = a.getB(); // <-warum schlägt dies fehl?
60
// const B& d(a.getB()); // <-warum schlägt dies fehl?
61
62
BSbs={1,2};
63
Bba(&bs);
64
constB&bb=ba;// dies schlägt erwartungsgemäß nicht fehl
Vlad Tepesch schrieb:> // const B& c = a.getB(); // <-warum schlägt dies fehl?
Weil der Compiler hier an dieser Stelle ein sog. 'temporary Object'
erzeugen muss, von dem er dann die Referenz bilden kann. getB liefert ja
ein Objekt und da du dieses Objekt nicht selbst kopierst, muss der
Compiler eine Kopie herstellen, weil ja das in der Funktion erzeugte
Objekt ein Ablaufdatum hat.
Aber: selbst wenn er dieses temporary object in der Optimierung wieder
los wird, entbindet das den Code an dieser Stelle nicht, dass der Copy
Konstruktor accessible ist. Und da er das nicht ist, setzt es einen
Fehler.
Im übrigen wär dir das sowieso abgestürzt.
Denn dieses B Objekt, welches die Funktion retourniert wird ja nach der
Anweisung zerstört. Womit der Aufrufer mit einer Referenz zurückbleit,
zu einem Objekt welches nicht mehr existiert.
Karl Heinz Buchegger schrieb:> Im übrigen wär dir das sowieso abgestürzt.>> Denn dieses B Objekt, welches die Funktion retourniert wird ja nach der> Anweisung zerstört. Womit der Aufrufer mit einer Referenz zurückbleit,> zu einem Objekt welches nicht mehr existiert.
Bzzzz, falsch.
Das temporäre Objekt lebt solange, wie die Referenz lebt.
Maximilian schrieb:> Karl Heinz Buchegger schrieb:>> Im übrigen wär dir das sowieso abgestürzt.>>>> Denn dieses B Objekt, welches die Funktion retourniert wird ja nach der>> Anweisung zerstört. Womit der Aufrufer mit einer Referenz zurückbleit,>> zu einem Objekt welches nicht mehr existiert.>> Bzzzz, falsch.>> Das temporäre Objekt lebt solange, wie die Referenz lebt.
Etwas vereinfacht, aber im Prinzip richtig. Hier das ganze in
Standard-Sprech:
— If the initializer expression is an rvalue, with T2 a class type, and
“cv1 T1” is reference-compatible with “cv2 T2,” the reference is bound
in one of the following ways (the choice is implementation-defined):
— The reference is bound to the object represented by the rvalue (see
3.10) or to a sub-object within that object.
— A temporary of type “cv1 T2” [sic] is created, and a constructor is
called to copy the entire rvalue object into the temporary. The
reference is bound to the temporary or to a sub-object within the
temporary.The constructor that would be used to make the copy shall be
callable whether or not the copy is actually done. [Example:
1
structA{};
2
structB:publicA{}b;
3
externBf();
4
constA&rca=f();
5
// Either bound to the A sub-object of the B rvalue,
6
// or the entire B object is copied and the reference
int i = a.getB().getA();
geht allerdings.
Maximilian schrieb:> Das temporäre Objekt lebt solange, wie die Referenz lebt.
genau das hätte ich erwartet.
Das in A::getB beim Return eine Kopie gemacht wird die Referenz
gespeichert wird.
angenommen der Copy-C'tor wäre nicht private, dann hätte ich folgendes
erwartet:
1
Bb=a.getB();
2 Copy-C'tor Aufrufe
- einen beim Return in der Klasse B
- einen bei der Initialisierung von b im aufrufenden Code
1
B&br=a.getB();
1 Copy-C'tor Aufruf
- einen beim Return in der Klasse B
Entsprechend dieser Annahmen hätte es mit dem private Copy-C'tor im
zweiten Fall klappen sollen.
Beide Fälle scheinen aber identisch (wenn man jetzt mal Polymorphie aus
dem Spiel lässt) und komplett anders als gedacht behandelt zu werden .
wohingegen
1
inti=a.getB().getA();
wie angenommen zu funktionieren scheint.
hier geschieht ein Copy-C'tor-Aufruf, der auch mit privatem copy c'tor
funktioniert.
Rolf Magnus schrieb:> Etwas vereinfacht, aber im Prinzip richtig. Hier das ganze in> Standard-Sprech:
das bezieht sich doch aber auf Vererbungsbeziehungen und Polymorphie .
> Rolf Magnus schrieb:>> Etwas vereinfacht, aber im Prinzip richtig. Hier das ganze in>> Standard-Sprech:>> das bezieht sich doch aber auf Vererbungsbeziehungen und Polymorphie .
Es bezieht sich auf die Initialisierung von Referenzen durch "rvalues"
von Klassen-Typen, egal ob es sich um eine Referenz auf den selben Typ
oder eine Basisklasse davon handelt. Daher ja auch:
> The reference is bound to the temporary
... wenn die Referenz vom selben Typ wie das Objekt ist ...
> or to a sub-object within the temporary.
... wenn sie von einer Basisklasse des Objekts ist.
Es steht ja auch nirgends in dem Text, daß “cv1 T1” und “cv2 T2” nicht
derselbe Typ sein dürfen, sondern nur, daß sie "reference compatible"
sein müssen.