[英]How to implement the same method in classes derived from an abstract base?
我有一個抽象的 class Job
和其他實現它的類,例如:
Waiter
和Builder
,他們都以同樣的方式實現了我的 function。
例如:
Waiter::changeScore()
{
score += top_score;
}
如何防止這種代碼重復?
約束:
我想保持Job
的抽象。
每個Waiter
或Builder
都有自己的top_score
值(在類和同一類的對象之間有所不同)。
並非抽象 class 的所有成員函數都必須是純虛函數(只要至少有一個是)。 您的changeScore
成員是作為“真實”基礎 class function 的理想人選。 此外,它不僅不需要是純virtual
,甚至根本不需要是virtual
(除非您希望多態性更改指向派生 class 的指針將看到的內容,對於該函數)。
由於每個 class (或對象)都有自己的top_score
值(如您所述),因此該(數據)成員也可以是“抽象”基礎 class 的一部分。
您甚至可以在基礎 class 中添加一個“虛擬”純虛擬 function(即使派生類也不打算使用它),只是為了確保不會意外創建實例。 例如,您的Job
class 可能有一個成員:
virtual int Dummy() = 0;
然后,任何派生的 class必須有一個覆蓋(無論多么微不足道),否則編譯器將不允許您聲明該 class 的實例。 所以,你的Waiter
class 需要類似的東西:
int Dummy override { return 1; }
以下代碼示例可能有助於/演示該想法:
#include <iostream>
#include <memory> // So we can use smart pointers
class Job {
public:
int score{ 0 }, top_score{ 0 };
public:
Job() { }
virtual ~Job() = default;
virtual void Dummy() = 0; // This is sufficient to make the class abstract!
void changeScore() {
score += top_score;
}
virtual void showName() {
std::cout << "Generic Job" << std::endl;
}
};
class Waiter : public Job {
public:
Waiter(int top = 5) { top_score = top; }
~Waiter() override = default;
void Dummy() override { } // We need this in order to use Waiter
void showName() override {
std::cout << "Waiter" << std::endl;
}
};
class Builder : public Job {
public:
Builder(int top = 10) { top_score = top; }
~Builder() override = default;
void Dummy() override { } // We need this in order to use Builder
void showName() override {
std::cout << "Builder" << std::endl;
}
};
int main()
{
Waiter w{ 6 }; // OK - uses explicit value for 'top' parameter
Builder b; // OK - uses default value for 'top' parameter
// Job j; // ERROR - Cannot instantiate abstract class
w.changeScore();
b.changeScore();
std::cout << w.score << std::endl;
std::cout << b.score << std::endl;
// Also, using pointers...
// Job* pj = new Job; // ERROR - Cannot instantiate abstract class
Job* pw = new Waiter; // OK - Now we can make use of polymorphism...
Job* pb = new Builder; // ...with either of these 2 "Job" pointers!
pw->showName();
pb->showName();
delete pw;
delete pb;
// Polymorphism also works with smart pointers (which you SHOULD be using) ...
// std::unique_ptr<Job> upj = std::make_unique<Job>(); // ERROR - Allocating an object of abstract class
std::unique_ptr<Job> upw = std::make_unique<Waiter>(15);
upw->changeScore();
std::cout << upw->score << ": ";
upw->showName();
std::unique_ptr<Job> upb = std::make_unique<Builder>(42);
upb->changeScore();
std::cout << upb->score << ": ";
upb->showName();
return 0;
}
您可以在基礎 class 中定義方法:
class Job {
private:
int score;
int top_score;
protected:
//protected constructor to be inherited by derived classes
Job(int top_score) : top_score(top_score) {}
//one pure virtual method is enough to make the class abstract
virtual void some_method() = 0;
public:
void changeScore() { //single method implementation
score += top_score;
}
//to use polymorphism you must use a virtual destructor, unless you use shared_ptr
virtual ~Job(){}
};
class Waiter : public Job {
public:
Waiter(int top_score) : Job(top_score) {}
// pure virtual methods must be overridden in all derived classes
void some_method() override{}
};
class Builder : public Job {
public:
Builder(int top_score) : Job(top_score) {}
void some_method() override{}
};
changeScore()
將在抽象 class 中實現,並可供所有派生類使用。
Waiter w(10); //top_score 10
Buider b(20); // top_score 20
b.changeScore();
w.changeScore();
您可以使changeScore
方法成為純虛擬方法並提供實現。 這看起來像這樣:
class Job {
int score{0};
int top_score{0};
public:
virtual void changeScore() = 0;
};
void Job::changeScore()
{
score += top_score;
}
然后你可以像這樣在子類中調用Job
base class 的changeScore
方法:
class Waiter : public Job {
public:
virutal void changeScore() override {
Job::changeScore();
}
};
這樣,如果要更改changeScore
,則不需要更改子類中的所有實現,而只需更改Job
class 中的實現即可。 這樣您就不需要任何虛擬方法,並且Job
class 仍然是抽象的,而子類中的覆蓋是微不足道的,如果您想更改它,您只有一個實現。
編輯:如果您想知道這個override
關鍵字來自哪里,它是在 C++11 中介紹的。 由於我不知道您使用的是哪個 C++ 版本,我只想指出這一點。 您可以在此處閱讀有關覆蓋說明符的信息
編輯二:關於曾經的孩子 class 有自己的top_score
,您應該通過這些子類的構造函數進行設置。 像這樣:
class Job {
protected:
int top_score{0};
Job(top) : top_score(top) {}
...
};
class Waiter : public Job {
public:
Waiter(int top): Job(top) {}
...
};
這樣每個孩子 class 都有自己的top_score
版本
編輯三:把所有的類放在一起看起來像這樣:
class Job {
protected:
int score{0};
int top_score{0};
Job(top) : top_score(top) {}
public:
virtual void changeScore() = 0;
};
void Job::changeScore()
{
score += top_score;
}
class Waiter : public Job {
public:
Waiter(int top): Job(top) {}
virutal void changeScore() override {
Job::changeScore();
}
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.