深入探索C++物件模型(六) Function語義學
阿新 • • 發佈:2019-02-14
1. 非虛成員函式指標(非靜態)。
取一個非靜態成員函式的地址,如果該函式是非虛擬函式,則得到的是它在記憶體中的真正地址,但是該地址並不完全,需要繫結與具體的類例項(物件)之上,藉助物件的地址(this指標)才可以被呼叫,例如:一個成員函式指標
- double (Point::* pmf)();
- double (Point::*coord)() = &Point::getX;//或者這樣初始化它:coord = &Point::getX;
- (orgin.*coord)();//或者這樣(ptr->*coord)();
- (coord)(&origin);
2. 指向虛成員函式的指標。
當一個函式指標指向一個虛成員函式時,例如:
- float (Point::*pmvf)() = &Point::z;//z為虛擬函式
- Point *ptr = new Point3d;//Point3d為Point的子類
- (ptr->*pmvf)();//效果等同於ptr->z();
- class Point {
- public:
- virtual ~ Point();
- float x();
- float y();
- virtualfloat z();
- };
- (*ptr->vptr[(int)pvmf])(ptr);//呼叫Point3d::z()
由於多重繼承(包括多重虛擬繼承)涉及到,子類中可能存在多個虛表,this指標的可能需要調整偏移,書中舉例了cfront的實現方法,引入一個結構體,在需要的時候儲存上述內容,結構體如下:
- struct __mptr {
- int delta;//虛基類或者多重繼承下的第二個以及之後基類的this指標偏移
- int index;//虛擬函式索引,非虛擬函式此值為-1
- union {
- ptrtofunc faddr;//非虛擬函式地址
- int v_offset;//虛基類或者多重繼承下的第二個以及之後基類的虛表位置
- };
- };
- (ptr->*pmvf)();
- (pmvf.index < 0) ?
- (*pmvf.faddr)(ptr)//非虛擬函式
- : (*ptr->vptr[pmvf.index])(ptr);//虛擬函式
1. 對於單一表達式的多重呼叫:
對如下incline函式:
- inline Point operator+ (const Point& lhs, const Point& rhs)
- {
- Point new_pt;
- new_pt.x(lhs.x() + rhs.x());//x()函式為成員變數_x的get,set函式
- return new_pt;
- }
- new_pt.x = lhs._x + x__5PointFV(&rhs);
- new_pt.x(lhs._x + rhs._x);
有如下inline函式:
- inlineint min(int i, int j)
- {
- return i < j ? i : j;
- }
- inlineint bar()
- {
- int minVal;
- int val1 = 1024;
- int val2 = 2048;
- minVal = min(val1, val2);//case 1
- minVal = min(1024, 2048);//case 2
- minVal = min(foo(), bar() + 1);//case 3
- return minVal;
- }
- minVal = val1 < val2 ? val1 : val2;
- minVal = 1024;
- int t1;
- int t2;
- minVal = (t1 = foo()), (t2 = bar() + 1), t1 < t2 ? t1: t2;
改寫上述min函式,引入一個區域性變數:
- inlineint min(int i, int j)
- {
- int minVal = i < j ? i : j;
- return minVal;
- }
- int minVal;
- int val1 = 1024;
- int val2 = 2048;
- minVal = min(val1, val2);
- int minVal;
- int val1 = 1024;
- int val2 = 2048;
- int __min_lv_minVal;//將inline函式區域性變數mangling
- minVal = (__min_lv_minVal = val1 < val2 ? val1: val2), __min_lv_minVal;
再複雜一些的情況,例如區域性變數加上有副作用的引數,會導致大量臨時性物件的產生:
- minVal = min(val1, val2) + min(foo(), bar() + 1);
會被擴充套件成為,注意逗號表示式,由左至右計算各個分式,以最右端的分式值作為最終值傳回:
- int __min_lv_minVal_00;
- int __min_lv_minVal_01;
- int t1;
- int t2;
- minVal = (__min_lv_minVal_00 = val1 < val2 ? val1 : val2, __min_lv_minVal_00) +
- (__min_lv_minVal_01 = (t1 = foo(), t2 = bar() + 1, t1 < t2 ? t1 : t2), __min_lv_minVal_01);