具体类和抽象类有什么区别?

我正在学习C ++,但是我对抽象类和具体类感到困惑。 一些真实世界的例子将不胜感激。

抽象类是声明了一个或多个方法但未定义的类,这意味着编译器知道这些方法是类的一部分,但不是该方法执行的代码。 这些被称为抽象方法。 这是一个抽象类的例子。

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

这声明了一个抽象类,它指定如果类是具体的,那么类的任何后代都应该实现抽象方法。 你不能实例化这个类,因为它是抽象的,毕竟,如果你调用成员绘制,编译器不知道要执行什么代码。 所以你不能做到以下几点:

 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 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) 

这个代码让你把你所有的形状收集到一个容器中。 如果场景中有许多形状和许多不同的形状,这使得它更容易。 例如,我们现在可以一次绘制出所有的形状,而这样做的代码甚至不需要知道我们所具有的不同types的形状。

现在最后我们需要知道为什么形状的绘制函数是抽象的,而不仅仅是一个空的函数,为什么我们不定义:

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

其原因是我们不是真的想要形状的物体,反正它们也不是真实的东西,它们是抽象的。 所以,为draw方法定义一个实现是没有意义的,甚至是空的。 使形状类抽象可以防止我们错误地实例化形状类,或者错误地调用基类的空画函数而不是派生类的画函数。 实际上,我们为任何想要像一个形状的类定义一个接口,我们说任何这样的类都应该有一个看起来像我们已经指定它应该的绘制方法。

为了回答你最后一个问题,没有任何“正常的派生类”这样的东西,每个类都是抽象的或具体的。 有抽象方法的类是抽象的,任何不是具体的类。 这只是一种区分两种types的方法。 基类可以是抽象的或具体的,派生类可以是抽象的也可以是具体的:

 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 */ }; 

抽象类不能用来创build一个对象。 而具体的类可以用来创build一个对象。

具体是指“ 存在于现实或实际经验中” 感官可感知; 真实''。 而抽象的意思是“ 不适用或不实际; 理论上的 “。

抽象类不能被实例化。 而具体的可以。

抽象类是具有一个或多个纯虚函数的类。 而具体的类没有纯粹的虚拟function。

具体类是一个可以用来创build对象的类。 一个抽象类不能用来创build一个对象(你必须扩展一个抽象类并创build一个具体的类来创build一个对象)。

假装有一台机器可以对原材料进行“加盖”并制造汽车。 压模是一个具体的类。 从这里我们可以创build汽车对象。 一个抽象的类将是这个压模的蓝图。 你不能从印模的蓝图上制造汽车,你需要先从蓝图上制作印模类。

这些其他问题涵盖了很多:

  1. 什么是抽象类?
  2. 抽象类与接口
  3. 什么是面向对象编程中的抽象数据types?
  4. 分离具体类的头文件 – C ++

抽象类不能被实例化,而具体可以。 抽象类作为派生类的“蓝图”,可以被实例化。

Car类(抽象),而Audi S4类(从Car派生)类是一个具体的实现。

基类与派生类是抽象类与具体类的正交概念。

基类是不能从任何其他类inheritance的类。 派生类从另一个类inheritance。

抽象类是具有一个或多个纯虚函数的类。 一个具体的类没有纯粹的虚拟。

抽象类可以是基类或派生类(它是从另一个抽象类派生的)。 一个具体的类也可以是基础的或派生的。 你甚至可以通过在派生类中添加一个纯虚函数来从一个具体类派生一个抽象类。 但是在一般情况下,有一个基本的抽象类和一个或多个具体的派生类。

使用抽象类的一个很好的例子是当你构build一个非常模块化的东西的时候。 假设您正在使用数据存储,但是这些数据可能位于MySQL数据库,SQLite数据库,XML文件或纯文本中。 为了在代码中保留这种多function性,您可以创build一个AbstractDatastore类来定义您想要用来从数据存储中获取信息的公共方法。 然后,创buildAbstractDatastore特定实现,例如XmlDatastoreSQLiteDatastore等。然后,您的程序只需要知道它正在获取AbstractDatastore ,并且它必须具有AbstractDatastore定义的那些函数,但它不知道或关心数据被存储或检索。

C ++ Faq Lite是在这类问题上寻找答案的绝佳网站。

在devise层面上,抽象基类(ABC)对应于抽象概念。 如果你问机修工是否修理车辆,他可能会想知道你想要什么样的车辆。 他有可能不修理航天飞机,远洋客轮,自行车或核潜艇。 问题是“车辆”这个词是一个抽象的概念(例如,除非你知道要build造什么样的车辆,否则你不能build造一个“车辆”)。 在C ++中,类Vehicle将是ABC,带有Bicycle,SpaceShuttle等等,派生类(OceanLiner是一种types的Vehicle)。 在现实世界的OO中,ABC遍布全球

抽象类是一个具有一个或多个纯虚拟成员函数的类。 你不能创build一个抽象类的对象(实例)

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

具体的类已经实现了所有的方法。 抽象类除了一些(至less有一个)未实现的方法之外的所有方法,以便可以扩展它并实现未实现的方法。

优点:通过从抽象类扩展,您可以获得基类的所有function,您将被“强制”实现未实现的方法。 所以这个类的devise者基本上迫使你在抽象方法中编写代码,然后才能使用这个类。