派生類轉換為基類
我們先明確幾個概念,如果我理解的不對希望能有大神指出錯誤。
第一是,無論哪種繼承方式,子類擁有父類的所有成員變量和成員函數,只是訪問權的問題。舉個例子
[cpp] view plaincopyprint?
#include <iostream>
using namespace std;
class A
{
public:
int i;
};
class B:public A
{
public:
int i;
};
int main()
{
B b;
b.i = 10;
A &a = b;
cout<<a.i<<endl;
}
#include <iostream>
using namespace std;
class A
{
public:
int i;
};
class B:public A
{
public:
int i;
};
int main()
{
B b;
b.i = 10;
A &a = b;
cout<<a.i<<endl;
}大家覺得最後輸出的結果是多少?
不是10.而是一個隨機值
我的電腦是1629101750。
這說明什麼問題呢,B中有兩個i,一個是父類的i,一個是自己的i.
但是一般程序設計的人絕對不會這麼設計的,因為一般名字一樣只要父類有,子類繼承就可以了。
但是考試的人,就會這麼出題了,這就是為什麼大家寫了那麼多年程序,很多面試題還是沒有見過,還是不會,第一是我們基礎不牢固,第二是這些地方的實用性其實不是那麼大,可能永遠不會用到。 不過如果為了提高自己,主要是為了防止出差,很多細節還是需要研究研究,多寫寫代碼,來驗證自己的思想是不是正確。
那麼派生類轉換為基類怎麼理解呢?
按照c++ primer 中的說法有兩種形式,一種就是給基類賦值,一種是轉換為基類的引用或者指針。派生類對象自身並沒有變成基類對象。
這兩種方式有一些細微的區別,很多時候最好使用常引用最為函數的入參,為什麼呢?因為引用少了賦值的操作,效率上面會高一些。
可以查看我寫的c++賦值的幾種方式, , 直接賦值應該是c語言中保留下來的,在c++中它的作用似乎就不大了,尤其對類和對象的。
大家看看下面的例子
[cpp]
#include<iostream>
using namespace std;
class A
{
public:
A();
A(A &a);
A(int i);
void set(A a);
int getI();
virtual void print();
private:
int i;
};
void A::print()
{
cout<<"A print"<<endl;
}
A::A()
{
}
A::A(A& a)
{
i = a.i;
}
A::A(int i)
{
this->i = i;
}
int A::getI()
{
return i;
}
void A::set(A a)
{
i = a.i;
}
class B: public A
{
public:
B(int i);
virtual void print();
private:
int k;
int i;
};
void B::print()
{
cout<<"B print"<<endl;
}
B::B(int i)
{
i = 5;
}
int main()
{
A a(10);
B b(5);
A a1(a);
A a2(b);
cout<<a1.getI()<<endl;
cout<<a2.getI()<<endl;
A a_next(20);
B b_next(15);
a1.set(a_next);
a2.set(b_next);
cout<<a1.getI()<<endl;
cout<<a2.getI()<<endl;
A &a3(b);
a1.print();
a2.print();
a3.print();
}
#include<iostream>
using namespace std;
class A
{
public:
A();
A(A &a);
A(int i);
void set(A a);
int getI();
virtual void print();
private:
int i;
};
void A::print()
{
cout<<"A print"<<endl;
}
A::A()
{
}
A::A(A& a)
{
i = a.i;
}
A::A(int i)
{
this->i = i;
}
int A::getI()
{
return i;
}
void A::set(A a)
{
i = a.i;
}
class B: public A
{
public:
B(int i);
virtual void print();
private:
int k;
int i;
};
void B::print()
{
cout<<"B print"<<endl;
}
B::B(int i)
{
i = 5;
}
int main()
{
A a(10);
B b(5);
A a1(a);
A a2(b);
cout<<a1.getI()<<endl;
cout<<a2.getI()<<endl;
A a_next(20);
B b_next(15);
a1.set(a_next);
a2.set(b_next);
cout<<a1.getI()<<endl;
cout<<a2.getI()<<endl;
A &a3(b);
a1.print();
a2.print();
a3.print();
}
覺得輸出的結果是什麼呢?
我這裡的答案是:
10
2293028
20
1628665296
A print
A print
B print
為什麼呢?
子類會調用父類的默認構造函數,根據上面的內容,上題中子類中包含父類的所有元素和方法,但是父類中的默認構造函數沒有初始化自己的i,這樣i就是個隨機值。
子類無論是給父類賦值,還是轉換為父類的構造函數,父類中的i永遠都沒有被初始化,所以結果就是上面的內容。
後面的print函數,我們又回顧了一下虛函數的用法,虛函數只對引用和指針有作用。切記!
基類轉換為派生類
這個不可以,這個轉換關系不存在。