Burada yapılacak çok farklı şeyler var. Kod geçerlidir, ancak sorunuzda yanlış bir varsayım yaptınız. Sen
"B :: Geta döner [...] kendisine değer 20 atanan, ondan sonra sıra"
(vurgu bana ait) Bu, doğru olmadığını söyledi. getA, nesneyi değiştirmek için değiştirmez. Bunu doğrulamak için, yöntem imzasına const
'u yerleştirebilirsiniz. O zaman tam olarak anlatacağım.
A getA() const {
cout << this << " in getA() now" << endl;
return (((A)*this) = 20);
}
Burada neler oluyor? Benim sample code baktığımızda (Bu cevap sonuna benim transkript kopyaladıktan):
A a = 10;
Bu yapıcı bir A bildirir. Oldukça dürüst. Bu bir sonraki satır:
B b; b.val_ = 15;
B herhangi kurucular yok, bu yüzden (A miras) onun val_ üyesine doğrudan yazmak zorunda. o superfically öyle gibi görünebilir, ancak bu b
değiştirmez
b.getA();
: Önümüzdeki çizgi A c = b.getA();
düşünmeden önce
, çok dikkatli daha basit ifade göz önüne almalıyız. Sonunda
, benim örnek kod
b.val_
yazdırır ve hala 15 eşit olduğunu görüyoruz. 20'ye değişmedi.
c.val_
elbette 20'ye dönüştü.
Bak getA
içinde ve (((A)*this) = 20)
bkz. Bunu kıralım:
this // a pointer to the the variable 'b' in main(). It's of type B*
*this // a reference to 'b'. Of type B&
(A)*this // this copies into a new object of type A.
Burada duraklamaya değer. Bu (A&)*this
veya hatta *((A*)this)
ise, daha basit bir çizgi olur. Ama bu (A)*this
ve bu nedenle bu A tipi yeni bir nesne oluşturur ve ilgili dilimi b'den b'ye kopyalar.
(Ekstra: Dilimin nasıl kopyalanabileceğini sorabilirsiniz. B&
referansımız var ve yeni bir A
oluşturmak istiyoruz.Varsayılan olarak, derleyici bir kopya oluşturucu A :: A (const A&)
oluşturur. Derleyici, bir başvuru B&
, bir const A&
için doğal olarak dökülebilir çünkü kullanabilirsiniz.)
Özellikle
this != &((A)*this)
. Bu sana bir sürpriz olabilir. (Ekstra: Öte yandan
this == &((A&)*this)
genellikle (
virtual
yöntemleri) olup olmamasına bağlı olarak) Şimdi bu yeni bir nesne olduğunu
, biz bu bu yeni değere sayısını koyar
((A)*this) = 20
bakabilirsiniz . Bu ifade, numaralı numaralı this->val_
etkilemez.
getA
'u A&
döndürecek şekilde değiştirmek bir hata olur. İlk olarak, operator=
dönüş değeri const A&
olup, bu nedenle A&
olarak döndüremezsiniz. Ancak dönüş türü olarak const A&
olsaydınız bile, bu getA içinde oluşturulan geçici bir yerel değişkenin referansı olur. Böyle şeyleri iade etmek doğru değildir.
Son olarak, Geta değeri tarafından kopya döndüren geçerli kod, güvende ve iyi olmasının nedeni c
olan Geta
A c = b.getA();
dan değeriyle döndürülür bu kopyayı alacağını görebilirsiniz -defined.
== aşağıdaki @Kerrek SB ve @Aaron McDaid, yardımı ile dikkatli incelemeden sonra tam programı ==
#include <iostream>
using namespace std;
struct A {
int val_;
A() { }
A(int val) : val_(val) { }
const A& operator=(int val) {
cout << this << " in operator= now" << endl; // prove the operator= happens on a different object (the copy)
val_ = val;
return *this;
}
int get() { return val_; }
};
struct B : public A {
A getA() const {
cout << this << " in getA() now" << endl; // the address of b
return (((A)*this) = 20);
// The preceding line does four things:
// 1. Take the current object, *this
// 2. Copy a slice of it into a new temporary object of type A
// 3. Assign 20 to this temporary copy
// 4. Return this by value
} // legal? Yes
};
int main() {
A a = 10;
B b; b.val_ = 15;
A c = b.getA();
cout << b.get() << endl; // expect 15
cout << c.get() << endl; // expect 20
B* b2 = &b;
A a2 = *b2;
cout << b2->get() << endl; // expect 15
cout << a2.get() << endl; // expect 15
}
'const A & operator = (int val) {val_ = val; } bir dönüş beyanı eksik? – ruakh
Eh, B :: getB' yok, ancak B :: getA' B örneğini değil (A'nın bir alt sınıfı olan) B örneğini döndürür. Çok belirsiz bir koddur, ancak yüzey, mükemmel okunaklı. –
@ruakh: Öyle görünüyor. :) – netcoder