繼承機制下編譯系統先執行函數
A. php類繼承的問題,子類繼承父類,實例化子類,先執行父類還是先執行子類
不是這個意思。所謂「實例化子類的對象前要先實例化父類中的內容,為父類初始化」,是指當子類正在實例化時,總是鏈式調用父類構造方法初始化父類空間。換句話說,子類的構造方法必須先調用父類的構造方法,完了才能幹別的初始化工作。如果子類沒有顯式調用語句,編譯器會隱式幫你加上。
如:
public class A{ public A() { }}public class B extends A{ public B() { }}等價於:
public class A{ public A() { super();//這里實際上是Object(); //其他初始化工作 }}public class B extends A{ public B() { super();//這里實際上是A(); //其他初始化工作 }}另外,如果有這種情況:
public class A{ X x=new X(); public A() { }}public class B extends A{ Y y=new Y(); public B() {//這是類A空間里的欄位都已經初始化完畢。 }}在成員y被賦值之前,x一定已經存在。換句話說,X x=new X();一定先於Y y=new Y();執行。
B. 在php中,子類extends繼承了父類,當子類和父類同時存在構造函數__construct先執行哪一個呢
1、如果父類和子類中都沒有顯式的定義__construct,在實例化子類對象時,只會隱含的調用子類自己的構造方法。
2、如果父類中有顯式的構造方法__construct,而子類中沒有定義__construct,在實例化子類對象時,就會調用父類中的構造方法。
3、如果父類和子類中都顯式的定義了__construct,在實例化子類對象時,只會調用子類自己的構造方法(這就像是子類重構了父類的構造方法),而如果也想要調用父類的構造方法的話,就需要在子類的__construct 方法中顯式的調用,(如 __construct(){ parent::_construct();})。
(2)繼承機制下編譯系統先執行函數擴展閱讀
子類的構造函數名與子類名相同。
在子類里父類的構造函數不會自動執行。
要在子類里執行父類的構造函數,必須執行類似以下語句:
$this->[父類的構造函數名()]
類的構造函數統一命名為__construct()。
子類的構造函數名也是__construct()(也是廢話)。
在子類里父類的構造函數會不會執行,分兩種情況:
1、如子類不定義構造函數 __construct(),則父類的構造函數默認會被繼承下來,且會自動執行。
2、如子類定義了構造函數 __construct(),因為構造函數名也是__construct(),所以子類的構造函數實際上是覆蓋(override)了父類的構造函數。這時執行的是該子類的構造函數。
這時如果要在子類里執行父類的構造函數,必須執行類似以下語句:parent::__construct();
C. C++多繼承方式構造函數的執行順序
明一個子類的對象穗冊時,首先梁族斗調用父類的構造函數,如果一個子類有多個父類時,則按照聲明的順序一次執行父類的構造函數,如class Derived : public Base1,public Base2 你先聲明Base1,後Base2,所以先調用Base1後Base2的構造函數,而與 Base2(z),Base1(y)的順序無關。
本人現在缺分,橡磨給我加分吧!
D. C++繼承的構造順序
1.構造函數
先看下面的類定義
class
B1 class B2
{ {
public: public:
int
i; int i;
B1() { i = 0;
} B2() { i = 0; }
virtual void f()
{} virtual void f() {}
}
; } ;
class
M1 class M2
{ {
public: public:
int
i; int i;
M1() { i = 0;
} M2() { i = 0; }
virtual void mf()
{} virtual void mf() {}
}
; };
class C : public B1, public B2
{
public:
virtual void f() {}
M1 m1;
M2 m2;
};
(1)編譯器會不會為C生成默認構造(default ctor)
編譯器只在需要時才會為一個類生成def
ctor。「需要時」指:
a.一個類有虛函數
b.一個類有虛基類
c.一個類的基類有def ctor
d.一個類的成員類有def ctor
在這里,class C符合c,d兩個條件,編譯器會為它生成def
ctor.
(2)默認構造的內容
編譯器生成的def ctor是這樣的
C::C()
{
B1::B1()
B2::B2()
設定虛表指針指向C的虛表
m1::M1()
m2::M2()
}
a.按聲明順序構造基類
b.設定虛表指針
c.按聲明順序構造成員類
(3)對自定義構造函數的改造
對於B1,B2,M1,M2,已有構造函數,但編譯器會對其改造,加入一些代碼,完成必要的初始化工作。改造後的ctor如下:(以B1為例)
B1::B1()
{
設定虛表指針指向B1的虛表
i = 0;
}
a.設定虛表指針
b.如果用戶寫有代碼(如i=0),則執行這些代碼
(4)綜合(2),(3),構造函數完整代碼如下
T::T()
{
按聲明順序構造基類
設定虛表指針
按聲明順序構造成員類
如果用戶寫有代碼,則執行這些代碼
}
在用戶代碼執行前,基類與成員類已構造完畢,虛指針已設定。
所以C的構造順序是:B1-〉B2-〉虛指針設定-〉m1-〉m2->C自己的代碼(如果有的話)
由(3)可知,每個類的ctor中,都會暫時將虛指針指向自己的虛表。調用B1::B1時,虛指針指向B1的虛表,然後在C::C中,虛指針被重新設定為C的虛表。
在繼承體系中,構造是由上而下的,B1或B2構造時,C還未構造。C構造時,B1和B2已構造完成。
所以在繼承體系中,一個類的構造函數執行時,該類的所有基類已構造完畢,虛指針已設定,所有成員類也已構造完畢。但該類的所有子類均未構造完成。
2.析構函數
(1)編譯器會不會為C生成析構函數(dtor)
編譯器只在需要時才會為一個類生成dtor。「需要時」指:
a.類的基類有析構
b.類的成員類有析構
與構造不同,少了兩點,因為在一個類析構時,這是一個破壞操作(destory),既然類以已經沒用了,何必再把虛指針設一下呢。
(2)析構的內容
編譯器生成的析構是這樣的
C::~C()
{
m2::M2()
m1::M1()
B2::B2()
B1::B1()
}
a.按聲明順序相反的順序析構成員類
b.按聲明順序相反的順序析構基類
這里的相反順序是C++標准規定的要求,不同編譯器都應做到,否則不符合標准(實際上編譯器或多或少都有不符標準的地方,當然不是指這里所說的順序問題)
(3)完整的析構的調用順序
對於已有析構函數的類,編譯器會對其改造,加入一些代碼,完成必要的工作。改造後的dtor如下:
T::~T()
{
設定虛表指針指向T的虛表
執行用戶代碼
按聲明順序相反的順序析構成員類
按聲明順序相反的順序析構基類
}
這是完整的析構的調用順序
在用戶代碼執行前,虛指針已重新設定,以便用戶代碼能正確執行。然後再析構成員類和基類。
所以,如果上面例子中的五個類都有析構函數的話,調用順序是:
虛指針設定-〉C自己的代碼->m2-〉m1-〉B2-〉B1
每個類的dtor中,都會暫時將虛指針指向自己的虛表。調用C::~C時,虛指針指向C的虛表,然後在B1::~B1中,虛指針被重新設定為B1的虛表。
可見,在繼承體系中,析構是由下而上的,B1或B2析構時,C已被析構。C析構時,B1和B2還未被析構。
所以在繼承體系中,一個類的析構函數執行時,該類的所有基類還未被析構,所有成員類也未被析構。但該類的所有子類均已析構完成。
3.虛函數
在構造或析構中調用虛函數,會怎樣.如:
B1::B1()
{
f();
}
調用的是B1::f()還是C::f()
答案是B1::f()
每個類的ctor中,都會暫時將虛指針指向自己的虛表。調用B1::B1時,虛指針指向B1的虛表
所以是B1::f()
如果在C的構造函數中調用f(),那就調用C::f()