程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> [C++]在構造函數及析構函數中調用虛函數,構造函數函數

[C++]在構造函數及析構函數中調用虛函數,構造函數函數

編輯:C++入門知識

[C++]在構造函數及析構函數中調用虛函數,構造函數函數


(ISO/IEC 14882:2011 section 12.7.4):

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2).
When a virtual function is called directly or indirectly from a constructor or from a destructor, including
during the construction or destruction of the class’s non-static data members, and the object to which the
call applies is the object (call it x) under construction or destruction, the function called is the final overrider
in the constructor’s or destructor’s class and not one overriding it in a more-derived class.

(ISO/IEC 14882:2011 section 12.7.4):

If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete
object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the
behavior is undefined.

在ctor及dtor中出現虛函數的調用,調用的虛函數實現為當前ctor/dtor處在的class那一級的實現。

也即是說class X的ctor/dtor中出現了繼承的虛函數vfun()的調用,不管X是否被其他類繼承,vfun是否被X的子類重寫,vfun的實現都為X一級的版本(X重寫的版本或者從X父類繼承來的版本)。

如果在X的ctor/dtor中調用vfun()的對象非X及其父類,則會導致undefined behavior。

//Example from ISO/IEC 14882:2011 section 12.7.4

struct V {
  virtual void f();
  virtual void g();
};
struct A : virtual V {
  virtual void f();
};
struct B : virtual V {
  virtual void g();
  B(V*, A*);
};
struct D : A, B {
  virtual void f();
  virtual void g();
  D() : B((A*)this, this) { }
};
B::B(V* v, A* a) {   f(); // calls V::f, not A::f   g(); // calls B::g, not D::g   v->g(); // v is base of B, the call is well-defined, calls B::g   a->f(); // undefined behavior, a’s type not a base of B }

 

如果在ctor/dtor內調用純虛函數會怎麼樣呢?

(ISO/IEC 14882:2011 section 10.4.6):

Member functions can be called from a constructor (or destructor) of an abstract class; the effect of making a
virtual call (10.3) to a pure virtual function directly or indirectly for the object being created (or destroyed)
from such a constructor (or destructor) is undefined.

在ctor/dtor內調用純虛函數會導致undefined behavior。


構造函數中間接調用虛函數

你是說如果把base::Out改成Out會出錯是吧?
因為如果不指明調用基類的虛函數,那麼編譯器就必須要等派生類同名的重載函數產生後,調用派生名的函數。而要生成派生類的Out函數,必須先生成派生類的實例。而生成派生類的實例,又必須先調用基類的構造函數。基類的構造函數中又調用了Out,而這時候派生類的實例還沒有生成,相應的Out函數也還沒生成,所以直接調用Out會導致無法鏈接到有效的派生類的Out函數,所以出錯。
 

c++中 析構函數中可以調用虛函數

根據Effective C++ (3rd Edition) ---- Item 9:
Never call virtual functions during construction or destruction.
(不要在構造函數和析構函數中調用虛函數)
其中舉例為:(英文)
class Transaction {
public:
Transaction();
virtual void LogTransaction() const = 0;
// ...
};
Transaction::Transaction()
{
// ...
LogTransaction();
}
class BuyTransaction : public Transaction {
public:
virtual void LogTransaction() const;
// ...
};
Consider what happen when this code is executed:
BuyTransaction b;
Clearly a BuyTransaction constructor will be called, but firt, a Transaction constructor must be called; base class parts of derived class objects are constructed before derived class parts are. The last line of the Transaction constructor calls the virtual function longTransaction, but this is where the surprise comes in. The version of logTransaction that't called is the one in Transaction, not the one in BuyTransaction -- even though the type of object being created is BuyTransaction. During base class construction, virtual functions never go down into derived classes. Instead, the object behaves as if it were of the base type. Informally speaking, during base class construction, virtual functions aren't.
There's a good reason for this seemingly counterintuitive behavior. Because base class constructors execute before derived class constructors, derived class data members have not been initialized when base class constructors run. If virtual functions called during base class constru......余下全文>>
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved