假設有base class如下:
class A
{
public:
A() { x = 0; }
A& operator = (const A &rhs) { x = rhs.x;}
private:
int x;
};
當然這種小場面是不需動用到operater = 的,在此只是為了舉例明確簡潔。
現在有個derived class如下:
class B : public A
{
public:
void do_something() {//.....}
};
B 並沒有多出任何data member。
現在當然可以進行以下的動作:
A *ptr1 = new B;
A *ptr2 = new B;
*ptr1 = *ptr2;
我們知道這樣會去引發 B 的base class,A,中的operator = ,而且在operator = 的
parameter list中,雖然型態是const A&,但是仍然可以傳B 進來,因為reference 就
像是個"寫得好看一點的pointer"。在此, [1;33m我再強調這裡用reference的好處,因為我的
問題和這個有關。 [m
接著考慮另一個derived class:
class C : public A
{
public:
C() { y=0;}
void do_something_else() {//.....}
private:
int y;
};
喔喔,現在因為C有多出自己的data member了,所以如果類似上面的程式碼:
A *ptr1 = new C;
A *ptr2 = new C;
*ptr1 = *ptr2;
這時base class的operator = 勢必無法提供我們的需求,因為還有 y 這個data
member需要拷貝。
於是我們第一個會想到要重載一個operator =,但是由於現在我的程式用到的是
"用base class的pointer指向derived class的object",所以應該要使用多型來
處理了。所以我把class A的A& operator =前面加上virtual。
所以,這個問題變成下面這樣:
class A
{
public:
A() { x=0;}
[1;33mvirtual [m A& operator = (const A &rhs) {x=rhs.x;}
private:
int x;
};
class C : public A
{
public:
C() {y=0;}
[1;31mA& operator = (const A &rhs) {//....} [m
private:
int y;
};
看到C 所重載的operator =函式原型(首先,函式原型當然要和class A中宣告的一
樣呀,不然就不是重載了),發現到一個重要問題: [1;33m無法在class C的operator =
的定義中寫下:
y = rhs.y; [m
因為rhs的型態可是const A&,就好像無法從base class的pointer直接去取用
derived class object的data member一樣。
有什麼解決方法嗎??
目前我只想到改成
virtual A* operator = ( [1;33mA* rhs [m)
這樣的話,在C重載的 A* operator = (A* rhs)中,就可以做down cast的動作來
處理這個問題。
可是,自己覺得這樣做滿爛的,因為在寫接下來的程式碼時,勢必寫成:
A *ptr1 = new C;
A *ptr2 = new C;
*ptr1 = ptr2;
這樣太奇怪了。
有沒有人有辦法parameter的型別仍然是用傳reference的方式,但是仍然可以處理
這個問題的??
==========================================================================
以上是我的思路啦,如果在中間有就想錯的話,就請大家指教了。
--
※ Origin: 楓橋驛站<bbs.cs.nthu.edu.tw> ◆ From: 202.39.11.114
This should be a rather normal problem. But it takes me some time
to solve it. Probably I did not have the problem before. Let me
use the example to show it. The details again can be found in
the book "More Effective C++", by Scott Meyers
class Base {
private :
int x ;
public :
Base( int a ) : x(a) {}
inline int getx() const { return x ; }
inline int setx( int a ) { x = a ; }
virtual Base& operator=( const Base& foo ) {
x = foo.x ;
return *this ;
}
virtual ostream& print( ostream& out ) const {
out << x ;
return out ;
}
friend ostream& operator<<( ostream& out , const Base& foo ) {
return foo.print(out) ;
}
};
class Derived : public Base {
private :
int y ;
public :
Derived( int a , int b ) : Base(a) , y(b) {}
virtual Base& operator=( const Base& foo ) {
setx( foo.getx() ) ;
/*
The following statement is the key but ugly. There
should be other nice ways.
const_cast : cast away to const
dynamic_cast : down cast the Base pointer to Derived
*/
y = (dynamic_cast<Derived*>(const_cast<Base*>(&foo)))->y ;
return *this ;
}
virtual ostream& print( ostream& out ) const {
out << getx() << " , " << y ;
return out ;
}
};
main() {
Base foo(3) ;
cout << foo << endl ;
Derived bar(4,5) ;
cout << bar << endl ;
Base *pt1 = new Derived(6,7) ;
Base *pt2 = new Derived(9,1) ;
cout << *pt1 << endl ;
cout << *pt2 << endl ;
*pt2 = *pt1 ;
cout << *pt1 << endl ;
cout << *pt2 << endl ;
}
The result is
3
4 , 5
6 , 7
9 , 1
6 , 7
6 , 7
--
> 吳維漢 -- wei...@math.ncu.edu.tw
> 中央大學數學系
--
[m [1;35m※ [1;33m發信站 [m[ [1;37;44m中央數學 織夢天堂 bbs.math.ncu.edu.tw [m]
‧ [1;32mFROM [m[ [1;37;44mziyou.math.ncu.edu.tw [m] [m