В чем разница между конкретным классом и абстрактным классом? - PullRequest
51 голосов
/ 27 января 2010

Я изучаю C ++, но меня смущает абстрактный класс и конкретный класс. Будем признательны за примеры из реальной жизни.

Ответы [ 9 ]

96 голосов
/ 27 января 2010

Абстрактный класс - это класс, для которого один или несколько методов объявлены, но не определены, это означает, что компилятор знает, что эти методы являются частью класса, но не то, какой код должен выполняться для этого метода. Это так называемые абстрактные методы. Вот пример абстрактного класса.

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

Это объявляет абстрактный класс, который указывает, что любые потомки класса должны реализовывать метод draw, если класс должен быть конкретным. Вы не можете создать экземпляр этого класса, потому что он абстрактный, в конце концов, компилятор не будет знать, какой код выполнять, если вы вызвали член 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 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)

Этот код позволяет вам собрать все ваши фигуры в один контейнер. Это делает это намного проще, если в вашей сцене много фигур и много разных фигур. Например, теперь мы можем нарисовать все фигуры за один раз, и код, который делает это, даже не должен знать о различных типах фигур, которые у нас есть.

Теперь, наконец, нам нужно знать, почему функция рисования формы является абстрактной, а не просто пустой функцией, т. Е. Почему мы просто не определили:

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 */
};
22 голосов
/ 15 ноября 2011

Абстрактный класс нельзя использовать для создания объекта. Принимая во внимание, что конкретный класс может использоваться для создания объекта.

Бетон означает «, существующий в реальности или в реальном опыте; воспринимается чувствами; реальный «». Принимая во внимание, что abstract означает ' не примененный или практический; theoritical .

Класс abstract не может быть создан. Принимая во внимание, что бетон можно.

Класс abstract - это класс, который имеет одну или несколько чисто виртуальных функций. В то время как класс concrete не имеет чисто виртуальных функций.

20 голосов
/ 27 января 2010

Конкретный класс - это класс, который можно использовать для создания объекта. Абстрактный класс нельзя использовать для создания объекта (вы должны расширить абстрактный класс и создать конкретный класс, чтобы иметь возможность затем создавать объект).

Притворись, что есть машина, которая может "штамповать" сырье и делать машину. Штампер - это конкретный класс. Из этого мы можем создавать автомобильные объекты. Абстрактный класс будет чертежами для штамповщика. Вы не можете делать машины из чертежей штамповщика, вам нужно сначала создать класс штамповок из чертежей.

3 голосов
/ 27 января 2010

Абстрактный класс не может быть создан, в то время как конкретный может. Абстрактный класс служит «планом» для производных классов, экземпляры которых могут быть созданы.

например. Car class (абстрактный), тогда как Audi S4 class (производный от Car) class является конкретной реализацией.

1 голос
/ 27 января 2010

Базовый класс и производный класс - это ортогональное понятие для абстрактного класса против конкретного класса.

Базовый класс - это класс, который не наследуется ни от какого другого класса. Производный класс наследует от другого класса.

Абстрактный класс - это класс, который имеет одну или несколько чисто виртуальных функций. У конкретного класса нет чистых виртуалов.

Абстрактный класс может быть базовым классом или производным классом (он является производным от другого абстрактного класса). Конкретный класс также может быть базовым или производным. Вы даже можете извлечь абстрактный класс из конкретного класса, добавив чистую виртуальную функцию в производный класс. Но в общем случае существует один базовый абстрактный класс и один или несколько конкретных производных классов.

1 голос
/ 27 января 2010

Хороший пример использования абстрактного класса - это когда вы создаете что-то очень модульное. Допустим, вы работаете с хранилищем данных, но эти данные могут находиться в базе данных MySQL, базе данных SQLite, XML-файле или в виде простого текста. Чтобы сохранить эту универсальность в вашем коде, вы можете создать класс AbstractDatastore, который определяет открытые методы, которые вы хотите использовать для получения информации из хранилища данных. Затем вы создаете свои конкретные реализации AbstractDatastore, такие как XmlDatastore, SQLiteDatastore и т. Д. Затем ваша программа просто должна знать, что она получает AbstractDatastore и что она должна иметь эти функции, определенные в AbstractDatastore, но он не знает и не заботится о том, как данные хранятся или извлекаются.

0 голосов
/ 27 января 2010

В конкретном классе реализован весь его метод. Абстрактный класс всех его методов, за исключением некоторых (по крайней мере один) метод (ы) не реализован, так что вы можете расширить его и реализовать не реализованный метод.

Преимущество: расширяясь от абстрактного класса, вы получаете все функциональные возможности базового класса, и вы будете «вынуждены» реализовать не реализованный метод. Поэтому разработчик класса в основном заставляет вас писать код в абстрактном методе, прежде чем класс вам пригодится.

0 голосов
/ 27 января 2010

C ++ Faq Lite - отличный сайт для поиска ответов на подобные вопросы.

На уровне проектирования абстрактный базовый класс (ABC) соответствует абстрактному понятию. Если бы вы спросили механика, ремонтирует ли он машины, он, вероятно, задастся вопросом, какую именно машину вы имели в виду. Скорее всего, он не ремонтирует космические корабли, океанские лайнеры, велосипеды или атомные подводные лодки. Проблема в том, что термин «транспортное средство» является абстрактным понятием (например, вы не можете построить «транспортное средство», если не знаете, какое транспортное средство построить). В C ++ класс Vehicle будет представлять собой ABC, а Bicycle, SpaceShuttle и т. Д. Будут производными классами (OceanLiner - это своего рода автомобиль). В реальном ОО азбуки появляются повсюду

Абстрактный класс - это класс, который имеет одну или несколько чисто виртуальных функций-членов. Вы не можете сделать объект (экземпляр) абстрактного класса

 class Shape {
 public:
   virtual void draw() const = 0;  // = 0 means it is "pure virtual"
   ...
 }; 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...