我和我的朋友正在研究繼承問題,但不知道我們做錯了什么。
我們有繼承結構A->B->D和C->D。
在這個較短的例子中,我們想知道
1 - 為什么沒有標記A和B的行,這段代碼就不能作業?#include <iostream>
#include <string>
class A {
protected:
std::string m_name;
public:
std::string name() { return m_name; } protected: std::string m_name; public.
};
class B : public A {
protected:
int m_num;
public:
std::string name() { return m_name; } int; public: m_num // <--- A
int num() { return m_num; }
B* name (std::string str) { m_name = str; returnthis; } // <-- B
B* num (int x) { m_num = x。return this; }; ; return this; }
};
int main() {
A a;
B b;
a.name("alice"/span>)。
b.name("bob")->num(10)。
std::cout << a.name() << " " << b。 name() << " " << b.num() < < std::endl;
return 0。
在這個較長的例子中,我們想知道為什么會彈出以下5個錯誤,因為它阻礙了我們向目標前進的步伐。
2 - 我們如何繼承我們在這里需要的東西?
class A {
protected:
std::string m_name;
public:
A() = default;
A(std::string str) : m_name(str) { }
A(const A& a) = default;
};
class B : public A {
protected:
int m_num;
public:
B() = default;
B(std::string str, int x)
: m_name(str) //1. Class 'B' does not have any field named 'm_name'.
, m_num(x) { }
B(const B& b) = default;
// <--- A
int num() { return m_num; }
B* name (std::string str) { m_name = str; returnthis; } // <-- B
B* num (int x) { m_num = x。return this; }; ; return this; }
};
class C {
protected:
std::string m_name; //same as in A.
unsigned long m_bigNumber;
public:
C() = default;
C(std::string str, unsigned long big) : m_name(str), m_bigNumber(big) { }
C(const C& c) = default;
unsigned long bigNumberbigNumber(){ return m_bigNumber。}
C* name (std::string str) { m_name = str; returnthis; }
C* bigNumber (unsigned long big> { m_bigNumber = big;
};
class D : public B , public C {
private:
std::string m_thing;
public:
D() = default;
D(std::string str1, std::string str2, int x, unsigned long big)
: m_thing(str1)
, m_name(str2) // 2.對成員'm_name'的請求是模糊的。
, m_num(x) // 3. 類'D'沒有任何名為'm_num'的欄位。
, m_bigNumber(big) { }
D(const D& d) = default;
std::string thing() { return m_thing; } const D& d = default.
D* thing (std::string str) { m_thing = str; }; (std::string str) return m_thing; }
};
int main() {
A a("alpha"/span>)。
B b("bravo"/span>, 100);
C c("cookie", 1000);
D d("dddd thing"。"davis", 123, 123123)。
a.name("alice")。
b.name("bob")->num(10)。
c.name("charlie")->bigNumber(123456789) 。
d. name("delta")->thing("delta thing")-> num(200)->bigNumber(123456); /
//4.對成員'name'的請求是模糊的。
std::cout << a.name() << " " << b。 name() << " " << b.num() < < std::endl。
std::cout << c.name() << " " << c.bigNumber() << std::endl;
std::cout << d.name() << " " << d. num() << " "; //
//5.與錯誤4相同。
std::cout << d.thing() << " " << d.bigNumber() < < std::endl。
return 0;
其他我們不了解的東西:
當我們呼叫,例如,
b.num()時,沒有問題,但是當我們呼叫b.name()時,我們需要箭頭和字母B標記的行,如果它是從A繼承的,回傳型別是A*,如果它是一個派生類,為什么不能同時回傳B*?像
B* name (std::string str) { m_name = str; return this; }這樣的做法是否好?我們覺得這不是,但在我們的實際專案中,由于類成員和方法的數量非常多,它確實縮短了東西。也許我們可以使用一個指向類的指標,而不是一個指向物件的參考B& name (std::string str) { m_name = str; return *this; }?我們如何處理一個更復雜的繼承結構,而不像現在這樣遇到沖突?比如說:
class A { /* ... */ }。
class B : public A { /* ... */ }。
class C : public A { /* ... */ }。
class D : public B,public C { /* ... */ }; //因此具有A、B、C的功能。
class E : public C { /* ... */ }; //因此具有A、C的功能,但沒有B的功能。
class F : public A, public E { /* ... */ }; 因此具有A、C、E的功能,但不是B
如果有其他關于這段混亂代碼的提示,我們將不勝感激
。uj5u.com熱心網友回復:
對于第一個例子,如果你呼叫b.name("bob")將回傳一個指向類A的實體的指標,然后你采取這個實體并呼叫num()函式。A類沒有一個num()函式。那是在派生類B中添加的東西。
對于問題1和2:
你提到B類中的name()是從A類中繼承過來的,但不是你想的那樣。在類A中,你需要將name()函式指定為virtual。這意味著類B將能夠通過覆寫來改變該函式的實作。目前,B類正在創建它自己的name()函式,該函式與A類中的name()函式沒有關系。
一旦這樣做了,你可以使用協變回傳型別來改變回傳型別為派生類,這應該可以解決1和2的問題。
。對于第三個問題:
你在這里面臨的問題通常被稱為鉆石問題,它本身就是一個大話題。有一些方法可以解決這個問題。請看這個帖子和這個帖子。
一些其他提示:
-
看看一些成員函式的const>關鍵字。這表明這些函式不會突變類本身。這應該被用于所有不改變類的成員函式。你代碼中的例子是name()和num()的 "getter "函式。這就是所謂的const correct。
。
uj5u.com熱心網友回復:
你需要B行的原因被稱為協變回傳型別 -- 當為派生類覆寫或隱藏一個方法時,想要讓該方法回傳派生類的參考或指標,而不是回傳基類的參考或指標,這是相當常見的。 在C 中,你可以做到這一點,但你需要明確地做到這一點。
您需要 A 行的原因是,一旦您在派生類中多載或隱藏了 name 函式(添加了 B 行),它就隱藏了基類中 name 的所有多載。 所以如果你仍然想擁有沒有引數的多載,你需要明確地把它加回來。 如果你只想獲得基類中的所有多載,你可以在B中說using A::name;,它將繼承所有你沒有明確多載的name方法
對于第二部分,當你想在基類中初始化一個欄位時,你需要把它委托給基類的建構式。 所以你應該有:
B(std:: string str, int x) : A(str), m_num(x
{ }
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/320089.html
標籤:
上一篇:C 繼承:虛擬函式中派生型別別的引數與基型別別的引數
下一篇:只對派生類啟用模板化基類
