c++中的(static) type和 (dynamic) type 概念是基于多態(tài)(polymorphism) ,例如:Vehicle*指針如果實(shí)際是指向一個(gè)Car對(duì)象,那么這個(gè)指針的靜態(tài)類型就是Vechicle,Car則是他的動(dòng)態(tài)類型。靜態(tài)類型發(fā)生在編譯器編譯時(shí),動(dòng)態(tài)類型發(fā)生在動(dòng)態(tài)綁定時(shí)。
我們常說的override(覆蓋)就是針對(duì)虛函數(shù)而言。
對(duì)虛函數(shù)的實(shí)現(xiàn)應(yīng)該說各個(gè)編譯器是不一樣的,大多數(shù)的編譯器是這樣的:
為每一個(gè)有虛函數(shù)的類增加一個(gè)虛表,這個(gè)虛表是靜態(tài)的,還有一個(gè)虛指針,為每個(gè)類對(duì)象。例如:
// Your original C++ source code
class Base {
public:
virtual arbitrary_return_type virt0(...arbitrary params...);
virtual arbitrary_return_type virt1(...arbitrary params...);
virtual arbitrary_return_type virt2(...arbitrary params...);
virtual arbitrary_return_type virt3(...arbitrary params...);
virtual arbitrary_return_type virt4(...arbitrary params...);
...
};
1 編譯器會(huì)為這個(gè)類的虛函數(shù)添加一個(gè)虛表,類似下面的:
// Pseudo-code (not C++, not C) for a static table defined within file Base.cpp
// Pretend FunctionPtr is a generic pointer to a generic member function
// (Remember: this is pseudo-code, not C++ code)
FunctionPtr Base::__vtable[5] = {
&Base::virt0, &Base::virt1, &Base::virt2, &Base::virt3, &Base::virt4
};
2 然后增加一個(gè)指向虛表的指針為每一個(gè)類對(duì)象,這個(gè)指針是隱藏的
// Your original C++ source code
class Base {
public:
...
FunctionPtr* __vptr; ← supplied by the compiler, hidden from the programmer
...
};
3 編譯器在構(gòu)造中初始化這個(gè)指針
Base::Base(...arbitrary params...)
: __vptr(&Base::__vtable[0]) ← supplied by the compiler, hidden from the programmer
...
{
...
}
在派生類中,它也會(huì)增加一個(gè)隱藏的虛表,但是它可以overrides基類的虛函數(shù)如:
// Pseudo-code (not C++, not C) for a static table defined within file Der.cpp
// Pretend FunctionPtr is a generic pointer to a generic member function
// (Remember: this is pseudo-code, not C++ code)
FunctionPtr Der::__vtable[5] = {
&Der::virt0, &Der::virt1, &Der::virt2, &Base::virt3, &Base::virt4
};
最后看看底層是如何調(diào)用的如:
void mycode(Base* p)
{
p->virt3();
}
主要三部分:
1.獲取隱藏的指向虛表的指針,并把它放在 register中如r1;
2.獲取指針r2=r1+3*4(假定一個(gè)指針有四個(gè)字節(jié)) ,并把它放到register中。
3 根據(jù)r2的地址調(diào)用函數(shù)。
所以說,調(diào)用一個(gè)虛函數(shù)至少和非虛函數(shù)差不多.
在這里我們可以看出一個(gè)虛指針的長度,至少是四個(gè)字節(jié),但是要注意編譯器對(duì)它的具體實(shí)現(xiàn)。
純虛函數(shù)怎樣用,下面的例子可以說明這個(gè)問題。
象下面的代碼就可以用純虛函數(shù)來實(shí)現(xiàn):
typedef std::vector<Vehicle*> VehicleList;
void myCode(VehicleList& v)
{
for (VehicleList::iterator p = v.begin(); p != v.end(); ++p) {
Vehicle& v = **p; // just for shorthand
// generic code that works for any vehicle...
...
// perform the "foo-bar" operation.
// note: the details of the "foo-bar" operation depend
// on whether we're working with a car or a truck.
if (v is a Car) {
// car-specific code that does "foo-bar" on car v
...
} else if (v is a Truck) {
// truck-specific code that does "foo-bar" on truck v
...
} else {
// semi-generic code that does "foo-bar" on something else
...
}
// generic code that works for any vehicle...
...
}
}
用純虛函數(shù)實(shí)現(xiàn)如下:
class Vehicle {
public:
// performs the "foo-bar" operation
virtual void fooBar() = 0;
};
typedef std::vector<Vehicle*> VehicleList;
void myCode(VehicleList& v)
{
for (VehicleList::iterator p = v.begin(); p != v.end(); ++p) {
Vehicle& v = **p; // just for shorthand
// generic code that works for any vehicle...
...
// perform the "foo-bar" operation.
v.fooBar();
// generic code that works for any vehicle...
...
}
}
也可以用繼承的方法來實(shí)現(xiàn)
class Car : public Vehicle {
public:
virtual void fooBar();
};
void Car::fooBar()
{
// car-specific code that does "foo-bar" on 'this'
... ← this is the code that was in {...} of if (v is a Car)
}
class Truck : public Vehicle {
public:
virtual void fooBar();
};
void Truck::fooBar()
{
// truck-specific code that does "foo-bar" on 'this'
... ← this is the code that was in {...} of if (v is a Truck)
}
有純虛函數(shù)的是抽象基類,強(qiáng)迫派生類接受基類的接口并實(shí)現(xiàn),在COM(組件)中比較常見,。
virtual constructor(虛構(gòu)造)的一個(gè)實(shí)現(xiàn)方法之一:
class Shape {
public:
virtual ~Shape() { } // A virtual destructor
virtual void draw() = 0; // A pure virtual function
virtual void move() = 0;
...
virtual Shape* clone() const = 0; // Uses the copy constructor
virtual Shape* create() const = 0; // Uses the default constructor
};
class Circle : public Shape {
public:
Circle* clone() const; // Covariant Return Types; see below
Circle* create() const; // Covariant Return Types; see below
...
};
Circle* Circle::clone() const { return new Circle(*this); }
Circle* Circle::create() const { return new Circle(); }
void userCode(Shape& s)
{
Shape* s2 = s.clone();
Shape* s3 = s.create();
...
delete s2; // You need a virtual destructor here
delete s3;
}
注意在VC6中必須寫成Shape*,VC7就不用改,支持返回類型可以變。