首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >具体类和抽象类之间的区别是什么?

具体类和抽象类之间的区别是什么?
EN

Stack Overflow用户
提问于 2010-01-28 02:04:13
回答 6查看 99.9K关注 0票数 58

我正在学习C++,但我对抽象类和具体类感到困惑。一些现实世界的例子将会很受欢迎。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-01-28 02:48:29

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

代码语言:javascript
复制
class shape {
public:
  virtual void draw() = 0;
};

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

代码语言:javascript
复制
shape my_shape();
my_shape.draw();

为了能够实际使用draw方法,您需要从这个抽象类派生类,该类实现了draw方法,使类具体化:

代码语言:javascript
复制
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,并使用它们的绘图方法:

代码语言:javascript
复制
circle my_circle(40, 30, 10);
rectangle my_rectangle(20, 10, 50, 15);
my_circle.draw();
my_rectangle.draw();

当然,现在的问题是,你为什么要这样做?难道你不能定义circle和rectangle类并去掉整个shape类吗?你可以,但这样你就不能利用他们的遗产了:

代码语言:javascript
复制
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)

这段代码让你将所有的形状收集到一个容器中。如果场景中有许多形状和许多不同的形状,这会使它变得容易得多。例如,我们现在可以一次绘制所有的形状,这样做的代码甚至不需要知道我们拥有的不同类型的形状。

现在我们终于需要知道为什么形状的绘制函数是抽象的,而不仅仅是一个空函数,也就是为什么我们不直接定义:

代码语言:javascript
复制
class shape {
public:
  virtual void draw() {
    /* do nothing */
  }
};

这样做的原因是,我们并不真的想要shape类型的对象,它们无论如何都不是真实的东西,它们将是抽象的。因此,为draw方法定义一个实现是没有任何意义的,即使是一个空的。使shape类抽象可以防止我们错误地实例化shape类,或者错误地调用基类的空绘制函数而不是派生类的绘制函数。实际上,我们为任何想要像形状一样行为的类定义了一个接口,我们说任何这样的类都应该有一个看起来像我们已经指定的绘制方法。

回答你的最后一个问题,没有“普通派生类”这样的东西,每个类都是抽象的或具体的。有抽象方法的类是抽象的,没有抽象方法的类是具体的。这只是一种区分两种类型类的方法。基类可以是抽象的,也可以是具体的;派生类可以是抽象的,也可以是具体的:

代码语言:javascript
复制
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 */
};
票数 106
EN

Stack Overflow用户

发布于 2010-01-28 02:10:29

具体类是可用于创建对象的类。抽象类不能用于创建对象(必须扩展抽象类并使具体类能够创建对象)。

假设有一台机器可以“盖章”原材料和制造一辆汽车。stamper是一个具体的类。由此,我们可以创建汽车对象。抽象类将是冲压机的蓝图。你不能根据冲压机的蓝图制造汽车,你需要首先根据蓝图制造冲压机类。

票数 20
EN

Stack Overflow用户

发布于 2010-01-28 02:08:24

抽象类不能实例化,而具体类可以实例化。抽象类充当派生类的“蓝图”,即可以实例化的类。

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

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2149207

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档