簡體   English   中英

在基類/派生類的成員函數/好友函數中派生*到Base *的轉換

[英]Derive* to Base* conversion in member function/friend function of base/derived class

這是代碼:

class B;
class C;
class D;
class A{
    public:
        virtual ~A(){}
        friend void gg(D* d);
        void ga(B *b,C* c,D* d);
    };

class B:protected A{
    public:
        void gb(B *b,C* c,D* d);
};
class C:public B{};
class D:public C{};

void A::ga(B *b,C*c,D*d){
    A *a1=b;  // error: 'A' is an inaccessible base of 'B'
    A *a2=c;  // error: 'A' is an inaccessible base of 'C'
    A *a3=d;  // error: 'A' is an inaccessible base of 'D'
}
void B::gb(B *b,C*c,D*d){
    A *a1=b;  // no problem here 
    A *a2=c;  //why do classes derived from B can sucessfully convert to A here?
    A *a3=d;  //why do classes derived from B can sucessfully convert to A here?
}
void gg(D* d){
    A* a=d;
}
int main(){
    B b;
    C c;
    D d;
    A a;
    gg(&d);  // error: 'A' is an inaccessible base of 'D'
    a.ga(&b,&c,&d);
    b.gb(&b,&c,&d);
    A a1(d); //error here;Does it mean the implicit conversion in the user code is also user code?
    A a4=d;  //same as above
    return 0;
}

這是有關派生基轉換的可訪問性的C ++入門:

•僅當D從B公開繼承時,用戶代碼才可以使用從基數轉換。如果D使用受保護的或私有的從B繼承,則用戶代碼不能使用轉換。

•不論D如何從B繼承,D的成員函數和D的朋友都可以使用到B的轉換。派生類的成員和朋友始終可以訪問直接基類的從派生到基的轉換。

•如果D使用公共或受保護從B繼承,則從D派生的成員函數和類的朋友可以使用派生基轉換。 如果D從B私有繼承,則此類代碼可能不使用轉換。

但這並沒有談到B從C / D到A的轉換或A從B / C / D到AI的轉換都認為第一次轉換會失敗而第二次轉換會成功。代碼)使我感到驚訝。

A類是B / C / D類的基類,因此我認為A中發生的從源到基的轉換(無效A :: ga(B *,C *,D *))會成功,但編譯器會抱怨從C ++引物的參考規則2中,我知道在B :: gb(B *,C *,D *)中從B到A的轉換會成功,但是為什么在B ::中從C / D到A的轉換是成功的gb(B *,C *,D *)也成功嗎? 為什么呢

這就是可訪問性的樂趣:

但這並沒有談到B中從C / D到A的轉換

繼承是protected :這意味着B知道繼承並且可以引用其基類,並且從B派生的類也具有此訪問權限。

B是否將A繼承為private ,情況將略有不同:在B中所有轉換仍將成功(因為B可以訪問私有A基),但是在派生類的函數中,所有這些轉換將失敗,因為它們將無法獲得乙的私生活(和繼承權)。

理由是標准:

  • (11.2 / 5) 如果可以訪問基類,則可以將指向派生類的指針隱式轉換為指向該基類的指針
  • (11.2 / 1) 如果使用受保護的訪問說明符將一個類聲明為另一個類的基類,則可以作為派生類的受保護成員訪問該基類的公共成員和受保護成員。 如果使用私有訪問說明符將一個類聲明為另一個類的基類,則可以將基類的公共成員和受保護成員作為派生類的私有成員進行訪問
  • (11.2 / 4) 如果(...)R出現在N類的成員或朋友中,並且B的發明的公共成員將是N的私有或受保護成員,則可以在R處訪問N的基本B類。
  • (5.10 / 3)進一步解釋說,如果無法訪問基礎,則派生到基礎的轉換是非法的。

轉換發生在A從B / C / D到A的過程中……我想……成功了。

A不是B的后裔。因此,它無權訪問其受保護的和私有的成員/繼承。

這是C ++編程語言中有關訪問說明符的聲明

基類的訪問規范控制對基類成員的訪問以及指針和引用從派生類類型到基類類型的轉換。 考慮從基類B派生的類D:

•如果B是私有基地,則其公共成員和受保護成員只能由D的成員功能和朋友使用。 只有 D的朋友和成員才能將D ∗轉換為B ∗。

•如果B是受保護的基礎,則其公共成員和受保護的成員只能由D的成員函數和朋友以及D的成員函數和類的朋友使用。 只有 D的朋友和成員以及D的朋友和類的成員才能使用D可以將D ∗轉換為B ∗。

•如果B是公共基地,則其公共成員可以由任何功能使用。 另外,D的成員和朋友以及D派生的類的成員和朋友可以使用其受保護的成員。任何函數都可以將D ∗轉換為B ∗。

發生從源到基的轉換時,進行轉換的代碼必須具有通過繼承層次結構從派生類到基類的所有可訪問性。

給定OP中的示例:

... //other same as before
void A::ga(B *b,C*c,D*d){
    A *a1=b;  // error: 'A' is an inaccessible base of 'B'
    A *a2=c;  // error: 'A' is an inaccessible base of 'C'
    A *a3=d;  // error: 'A' is an inaccessible base of 'D'  <<-- I'll explain this conversion 
}
...//other same as before

轉換D->A發生在A中,因此A必須具有轉換D->C->B->A的可訪問性,我們看到D->CC->B是公共的,但B->A受保護,這意味着D可以一直轉換為B,但是將在B->A中的B->A處停止。要在B->A中進行轉換,我們必須根據受保護的規則將A類聲明為B或C或D類的好友。編譯器不會再抱怨了。

現在,如果繼承自A的類B和繼承自B的類C都繼承為私有怎么辦?

... // others same as before
class B:private A{ // inherited as private
    public:
        void gb(B *b,C* c,D* d);
};
class C:private B{};  // inherited as private 
class D:public C{};

void A::ga(B *b,C*c,D*d){
    A *a1=b; 
    A *a2=c;  
    A *a3=d;  //    <--------------------------- I'll explain this 
}
void B::gb(B *b,C*c,D*d){
    A *a1=b; 
    A *a2=c; 
    A *a3=d;  //   <============================ and this
}
...  // others same as before

在函數A::ga ,轉換D->C可以工作,但是在C->BB->A失敗,因此我們必須將A類同時聲明為B和C類的好友,以獲取可訪問性。

在函數B::gb ,轉換D->CB->A (根據私法)可以工作,但是C->B失敗,因此我們必須將B類聲明為C類的好友,以實現D->A轉換在B中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM