我正在學習 C ,但我不斷收到一個我不明白的奇怪編譯錯誤。我將代碼簡化為以下示例:
#include <iostream>
class A {
public:
static A foo()
{
A a;
return a;
}
};
class B : A
{
public:
static B boo()
{
B b;
return b;
}
};
typedef A (*function)(void);
int main() {
function f1 = A::foo;
function f2 = B::boo; //error
return 0;
}
我收到以下錯誤:
無法使用“B ()”型別的左值初始化“函式”型別的變數(又名“A (*)()”):不同的回傳型別(“A”與“B”)
誰能解釋為什么它不起作用?既然是, isB的孩子,為什么從“void to ”指向的函式指標不像從“void to ”指向的函式指標?ABABA
uj5u.com熱心網友回復:
確實,C 允許將指向子類的指標轉換為指向父類的指標(取決于某些條件)。
確實,C 允許對子類的參考轉換為對父類的參考(也受制于某些條件)。
但是,這并不意味著 C 允許將指向回傳父類的函式的指標轉換為指向回傳子類的函式的指標。這是顯示的代碼試圖做的事情,這是不允許的。
這回答了你“為什么”的問題:因為這在 C 中是不允許的。至于為什么,“為什么”;這主要是由于一些實際的考慮,但這并不重要,這只是 C 規則所不允許的。
uj5u.com熱心網友回復:
您function聲稱它應該回傳 anA但boo回傳 a B,因此:
typedef A (*A_function)();
typedef B (*B_function)();
int main() {
A_function f1 = A::foo;
B_function f2 = B::boo;
}
您可以通過從兩個函式回傳基類指標來解決它:
class A {
public:
virtual ~A() = default; // for destruction via a base class pointer
static A* foo() { return new A; }
};
class B : A { // you should probably use public inheritance
public:
static A* boo() { return new B; } // creates a B but returns an A*
};
typedef A* (*function)();
int main() {
function f1 = A::foo;
function f2 = B::boo;
}
或者更好的是,使用智能指標不必delete手動實體化:
#include <memory>
class A {
public:
virtual ~A() = default;
static std::unique_ptr<A> foo() { return std::make_unique<A>(); }
};
class B : public A {
public:
static std::unique_ptr<A> boo() { return std::make_unique<B>(); }
};
using function = std::unique_ptr<A>(*)();
int main() {
function f1 = A::foo;
function f2 = B::boo;
}
uj5u.com熱心網友回復:
既然
B是 的孩子是A,BA
不完全的。由于B是 的子物件A,因此任何B物件也是A物件。但是,這不是對稱的,因此聲稱是 是B夸大其詞A。聲稱“a Bis an A”是正確的,但去掉不定冠詞(“a”和“an”)會使該斷言不成立。
為什么“void to
B”的函式指標不像“void to”的函式指標A?
因為B不是A。回傳型別不同,所以函式型別也不同。可以將B物件轉換為A物件(通過復制A子物件),但這是一個額外的步驟。如果你要寫
A value = B::boo();
然后編譯器插入一個轉換 from Bto Aafterboo()被呼叫。轉換可能不需要機器指令(也稱為“無操作”),但它仍然存在。(轉換的一個副作用是不能省略復制。)
A value = static_cast<A&&>(B::boo());
如果您要boo()通過 type 的函式指標呼叫A(*)(),則沒有什么可以告訴編譯器插入轉換。跳過轉換可能是一個問題,特別是如果B物件具有不在物件中的資料成員A,特別是如果這些資料成員具有非平凡的解構式。
該語言不會嘗試在跳過轉換是問題和不是問題的情況之間劃清界限。這適用于回傳型別和引數型別。分配給指標的函式型別必須與指標的型別完全匹配,無需轉換。
這就是函式物件(如std::function)有用的地方。Astd::function<A()>可以存盤A:foo或B::boo。這是因為函式物件會適應并記錄需要進行哪些轉換,類似于直接呼叫函式時發生的情況。與函式指標不同,函式物件不需要型別完全匹配。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/489676.html
下一篇:C#獲取派生類屬性
