簡體   English   中英

具體類和抽象類之間有什么區別?

[英]What is the difference between a concrete class and an abstract class?

我正在學習C ++,但我對抽象類和具體類感到困惑。 一些現實世界的例子將不勝感激。

抽象類是一個聲明了一個或多個方法但未定義的類,這意味着編譯器知道這些方法是類的一部分,而不是該方法要執行的代碼。 這些被稱為抽象方法。 這是一個抽象類的示例。

class shape {
public:
  virtual void draw() = 0;
};

這聲明了一個抽象類,它指定類的任何后代應該實現draw方法(如果該類是具體的)。 您無法實例化此類,因為它是抽象的,畢竟,如果您調用成員繪制,編譯器將不知道要執行的代碼。 所以你不能做到以下幾點:

shape my_shape();
my_shape.draw();

為了能夠實際使用draw方法,您需要從這個抽象類派生類,它實現了draw方法,使類具體化:

class circle : public shape {
public:
  circle(int x, int y, int radius) {
    /* set up the circle */
  }
  virtual draw() {
    /* do stuff to draw the circle */
  }
};

class rectangle : public shape {
public:
  rectangle(int min_x, int min_y, int max_x, int max_y) {
    /* set up rectangle */
  }
  virtual draw() {
    /* do stuff to draw the rectangle */
  }
};

現在,您可以實例化具體對象circle和rectangle並使用它們的draw方法:

circle my_circle(40, 30, 10);
rectangle my_rectangle(20, 10, 50, 15);
my_circle.draw();
my_rectangle.draw();

當然問題是,你為什么要這樣做? 難道你不能定義圓形和矩形類並取消整個形狀類嗎? 你可以,但是你將無法利用他們的繼承:

std::vector<shape*> my_scene;
my_scene.push_back(new circle(40, 30, 10));
my_scene.push_back(new rectangle(20, 10, 50, 15));
std::for_each(my_scene.begin(), my_scene.end(), std::mem_fun_ref(&shape::draw)

這段代碼讓你將所有形狀收集到一個容器中。 如果你的場景中有很多形狀和許多不同的形狀,這將使它變得容易多了。 例如,我們現在可以一次性繪制所有形狀,而這樣做的代碼甚至不需要知道我們擁有的不同類型的形狀。

最后我們需要知道為什么shape的draw函數是抽象的,而不僅僅是一個空函數,即為什么我們不定義:

class shape {
public:
  virtual void draw() {
    /* do nothing */
  }
};

這樣做的原因是我們並不真正想要類型為對象的對象,無論如何它們都不是真實的東西,它們是抽象的。 因此,為draw方法定義一個實現沒有任何意義,即使是空方法。 使形狀類抽象可以防止我們錯誤地實例化形狀類,或者錯誤地調用基類的空繪制函數而不是派生類的繪制函數。 實際上,我們為任何想要表現形狀的類定義一個接口,我們說任何這樣的類都應該有一個看起來像我們已經指定它的draw方法。

為了回答你的最后一個問題,沒有任何“普通派生類”這樣的東西,每個類都是抽象的或具體的。 具有任何抽象方法的類是抽象的,任何不具體的類都是具體的。 它只是區分兩類類的一種方法。 基類可以是抽象的也可以是具體的,派生類可以是抽象的也可以是具體的:

class abstract_base {
public:
  virtual void abstract_method1() = 0;
  virtual void abstract_method2() = 0;
};

class concrete_base {
public:
  void concrete_method1() {
    /* do something */
  }
};

class abstract_derived1 : public abstract_base {
public:
  virtual void abstract_method3() = 0;
};

class abstract_derived2 : public concrete_base {
public:
  virtual void abstract_method3() = 0;
};

class abstract_derived3 : public abstract_base {
public:
  virtual abstract_method1() {
    /* do something */
  }
  /* note that we do not provide an implementation for
     abstract_method2 so the class is still abstract */
};

class concrete_derived1 : public concrete_base {
public:
  void concrete_method2() {
    /* do something */
  }
};

class concrete_derived2 : public abstract_base {
public:
  virtual void abstract_method1() {
    /* do something */
  }
  virtual void abstract_method2() {
    /* do something */
  }
  /* This class is now concrete because no abstract methods remain */
};

抽象類不能用於創建對象。 具體類可用於創建對象。

具體意味着“ 在現實中或在實際經驗中存在; 被感官察覺; 真實''。 然而, 抽象意味着“ 不適用或不實際; 理論上的。

無法實例化抽象類。 然而, 具體的可以。

抽象類是具有一個或多個純虛函數的類。 具體類沒有純虛函數。

具體類是可用於創建對象的類。 抽象類不能用於創建對象(必須擴展抽象類並使具體類能夠創建對象)。

假裝有一台機器可以“蓋章”原材料並制造汽車。 壓模是一個具體的類。 由此我們可以創建汽車對象。 抽象類將是壓模的藍圖。 你不能用壓模的藍圖制造汽車,你需要先從藍圖上制作壓模類。

抽象類不能在具體的情況下實例化。 抽象類充當派生類的“藍圖”,可以實例化。

例如, Car類(摘要),而Audi S4級(源自Car )類是具體實施。

使用抽象類的一個很好的例子是當你構建一個非常模塊化的東西時。 假設您正在使用數據存儲,但該數據可能位於MySQL數據庫,SQLite數據庫,XML文件或純文本中。 要在代碼中保留這種多功能性,可以創建一個AbstractDatastore類,它定義要用於從數據存儲區獲取信息的公共方法。 然后你創建了AbstractDatastore特定實現,比如XmlDatastoreSQLiteDatastore等。然后,你的程序只需要知道它正在獲取AbstractDatastore並且它必須具有在AbstractDatastore定義的那些函數但是它不知道或關心數據如何存儲或檢索。

基類與派生類是抽象類與具體類的正交概念。

基類是不從任何其他類繼承的基類。 派生類確實從另一個類繼承。

抽象類是具有一個或多個純虛函數的類。 具體類沒有純虛擬。

抽象類可以是基類,也可以是派生類(它是從另一個抽象類派生的)。 具體類也可以是基類或派生類。 您甚至可以通過向派生類添加純虛函數,從具體類派生抽象類。 但在一般用途中,有一個基本抽象類和一個或多個具體派生類。

C ++ Faq Lite是一個很好的網站,可以在這類問題上尋找答案。

在設計層面,抽象基類(ABC)對應於抽象概念。 如果你問機修工他是否修理了車輛,他可能會想知道你的車輛是什么樣的。 他可能無法修理航天飛機,遠洋輪船,自行車或核潛艇。 問題是“車輛”這個詞是一個抽象的概念(例如,你不能建造一個“車輛”,除非你知道要建造什么樣的車輛)。 在C ++中,類Vehicle將是一個ABC,其中Bicycle,SpaceShuttle等是派生類(OceanLiner是一種類型的Vehicle)。 在現實世界的OO中,ABC出現在各地

抽象類是具有一個或多個純虛擬成員函數的類。 您不能創建抽象類的對象(實例)

 class Shape {
 public:
   virtual void draw() const = 0;  // = 0 means it is "pure virtual"
   ...
 }; 

具體類已實現其所有方法。 除了一些(至少一個)方法之外,抽象類的所有方法都是未實現的,這樣您就可以擴展它並實現未實現的方法。

優點:通過從抽象類擴展,您將獲得基類的所有功能,並且您將被“強制”實現未實現的方法。 因此,類的設計者基本上強迫您在類對任何用途之前在抽象方法中編寫代碼。

暫無
暫無

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

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