類(class)能不能自己繼承自己?
突發奇想而已,請各位講講這些OOP語言能不能這樣呢?
如果能,請舉例; 否則,請說明原因.
不行,繼承關係會出現環。
假設類A繼承類A。
那麼要新建一個類A的對象,就必須先建立一個類A父類的對象。這是一個遞歸的過程,而且沒有終止條件。會死循環的。
從編譯的角度講,聲明類A的時候需要用到它的父類,但是此時類A還沒有聲明。所以是不可行的。
=== 猶豫了一下的分割線 ===評論區有同學說了模版這種妖術可以解決。我仔細想了想,貌似還真有編程語言可以實現。比如在Lua中一種常見的繼承方式是使用metaclass。此時只要將metaclass指向自己就好了。此時的繼承關係依舊是個環…區別在此處的環形繼承關係是在運行時的時候創建的,所以可以硬上,之前的是要求運行前就搞定的,所以在創建的時候會有問題…此時的繼承關係不影響你使用:P。同理其他的像JS啊之類的東東也可以有類似的用法。然而並沒有什麼卵用……嚴格意義上的繼承不可能實現,否則將會出現循環依賴.若分離內存布局的"繼承",則可以通過CRTP繼承包含自身類型信息的基類;如@白如冰 的答案里提到的;(這應該說是更像將自身的類型信息"傳遞"給了基類,也算是一種非嚴格意義另類的自身繼承_(:3」∠)_ ).這種"繼承"自身還是有需求的,基於性能的考慮;主要是通過CRTP可實現靜態多態:在編譯期確定函數的調用省去了虛表Demo:
#include &
template&
class Base
{
public:
void func() //call the function implemented in derived class
{
static_cast&<_Ty*&>(this)-&>func();
}
};
class Derived_A
:public Base&
{
public:
void func() //implement
{
std::cout &<&< "Derived Class A" &<&< std::endl;
}
};
class Derived_B
:public Base&
{
public:
void func() //implement
{
std::cout &<&< "Derived Class B" &<&< std::endl;
}
};
template&
void invoke(Base&<_Ty&> obj)
{
obj.func();
}
int main()
{
Derived_A A;
Derived_B B;
invoke(A);
//Output: Derived Class A
invoke(B);
//Output: Derived Class B
return 0;
}
直接繼承當然不行,但是這種trick用的還是很多的。
class A : public TemplateClass&{
...};
因為繼承關係是非對稱(反對稱且非自反)的。
如果已經有一個類A了,可以再定義一個新的類A,讓它繼承原來的A。
class A(A):
pass
這個新的A,就繼承了一個原來也叫A現在沒有名字綁定的類了。
當然,這和繼承自己還是不太一樣。Pythonclass Self {
};class Derived : public Self {};加上模板就可以自己繼承自己了,見PCL的源碼:
template&
自己和自己是一樣的,不用寫繼承,一直是等價的,由此可見,這個問題真是蛋疼,自己繼承自己你是要做什麼?
不行,遞歸定義了
你先問問類什麼場景下需要繼承自己,有需求了,設計不是問題。
有一天你可以生出自己得時候就可以了
別的語言不知道
c++里被繼承的類必須是完整定義的
所以繼承自己會報錯不行。 假設 A 有一個對象是 A obj 。那麼 sizeof(obj) 是多大?sizeof(obj) = infinite你會說 sizeof(obj) = 0 ? 不行,C++ 標準規定,任何對象的大小至少是1。為啥? 因為要保證每一個對象有唯一的地址。 A objs[100];如果 sizeof(A) == 0 ,那麼 objs[0] 和 objs[1] 的地址就相同了。沒有辦法區別這兩個對象的地址了。
理論上可以·顯然編譯過不去,好的,當然你可以改編譯器。然後你就會發現。A extend A,那A還不就是A……顯然沒什麼用
命名空間不允許
推薦閱讀:
※新手求教python 面向對象編程的一個問題?
※為什麼有的人連OO、FP等基本的語言概念都搞不清楚,卻整天吹噓OO/FP的好處?
※我有很多隻筆(鉛筆、圓珠筆),但是我聲明一個類「筆」作為各種筆的父類有什麼意義呢?
※為何少部分語言如C++和python要堅持引入多繼承?
TAG:面向對象編程 |
