![](/img/trans.png)
[英]C++ - Change object pointed by base class (in an operator oveloading function returning reference to base class)
[英]in C++, why compiler does not understand which object is pointed by base class object at compile time?
在C ++中,為什么編譯器在編譯時不理解基類對象指向哪個對象?
對於前。
int Add(int nX, int nY)
{
return nX + nY;
}
int Subtract(int nX, int nY)
{
return nX - nY;
}
int main()
{
// Create a function pointer and make it point to the Add function
int (*pFcn)(int, int) = Add;
cout << pFcn(5, 3) << endl; // add 5 + 3
pFcn = Subtract;
cout<< pFcn(5,3)<<endl // pefrom 5-3
return 0;
}
上面的代碼段是后期綁定或動態綁定的示例。
在上面的示例中,只有在編譯時,我們才知道第一個Add函數將通過pFcn調用,然后Subtract函數將被調用。 那么,為什么即使編譯器只知道在編譯時要調用哪個函數,也可以將其稱為動態綁定的示例呢?
我的問題也與虛擬功能有關。 考慮跟隨前,
class Base {
public:
void NonVirtual() {
cout << "Base NonVirtual called.\n";
}
virtual void Virtual() {
cout << "Base Virtual called.\n";
}
};
class Derived : public Base {
public:
void NonVirtual() {
cout << "Derived NonVirtual called.\n";
}
void Virtual() {
cout << "Derived Virtual called.\n";
}
};
int main() {
Base* bBase = new Base();
Base* bDerived = new Derived();
bBase->NonVirtual();
bBase->Virtual();
bDerived->NonVirtual();
bDerived->Virtual();
}
動態綁定在這里發生。 在運行時確定要調用哪個函數。 那么,為什么編譯器在編譯時不能僅決定調用哪個函數呢?
在一般情況下,使用函數指針請求后期綁定,但是如果能夠證明只有一個函數可以綁定,那么足夠聰明的編譯器可以優化該請求並進行早期綁定。 按條件優化規則允許這樣做 :
pFcn
)。 考慮一下,您可能會以編譯器無法進行早期綁定的方式傳遞函數指針,這可能是因為它不夠聰明,無法檢測到可能,或者是因為它與無法觀察的代碼進行交互:
using BinaryIntegerOperator = int (*)(int, int);
int Add(int a, int b) { return a + b; }
int Subtract(int a, int b) { return a - b; }
extern int accumulate(
int initial,
int *first,
std::size_t count,
BinaryIntegerOperator op
);
現在,您可以將Add
或Subtract
作為第四個參數。 被調用的函數可能不是同一二進制文件的一部分(也許它是動態鏈接庫的一部分),因此后期綁定是不可避免的accumulate()
應該已經由其他編譯器進行了編譯。
在編譯系統可以證明只有一個函數可以調用的情況下,允許但不要求刪除間接調用並直接調用該函數。 這適用於函數指針和虛擬方法分派。 通常,對於虛擬方法,優化將作為鏈接時間優化的一部分進行,鏈接器會意識到其中只有給定類的一個實例具有虛擬方法,或者可能沒有任何類覆蓋虛擬方法。
我不確定優化是否被認為非常重要,但是我希望這兩種情況都會在使用最佳編譯器的簡單情況下發生。 (第一個示例將脫離相當標准的編譯器優化技術。幾乎可以肯定的是,針對vtables進行此操作需要經過專門構建的優化過程,因為編譯器必須知道vtable在運行時是如何修改或不修改。
通常,簡化使用某種機制並不意味着不使用指定的機制。 這就是為什么即使編譯器可以證明函數指針沒有有趣的動態行為,也可以說函數指針是動態綁定的原因。
給定上面更新的代碼,請考慮以下事項:
int main(int argc, char **argv) {
Base* bBase = new Base();
Base* bDerived = new Derived();
// Use test on argc to abstract arbitrary computation.
Base *one_or_the_other = (argc > 1) ? bDerived : bBase;
one_or_the_other->NonVirtual();
one_or_the_other->Virtual();
}
編譯器無法再在編譯時確定要調用第二次調度的虛擬方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.