Вопрос

Для чего люди здесь используют конструкторы абстрактного базового класса C++ в полевых условиях?Я говорю о чистых классах интерфейса, не имеющих членов данных и нечистых виртуальных членов.

Может ли кто-нибудь продемонстрировать какие-либо идиомы, которые полезным образом используют конструкторы ABC?Или просто природе использования ABC для реализации интерфейсов свойственно то, что они остаются пустыми, встроенными и защищенными?

Это было полезно?

Решение

Может ли кто-нибудь продемонстрировать какие-либо идиомы, которые полезным образом используют конструкторы ABC?

Вот пример, хотя это надуманный и необычный пример.

Вы можете использовать его для хранения списка всех экземпляров:

class IFoo
{
private:
  //static members to keep a list of all constructed instances
  typedef std::set<IFoo*> Set;
  static Set s_set;

protected:
  //new instance being created
  IFoo()
  {
    s_set.insert(this);
  }

public:
  //instance being destroyed
  virtual ~IFoo()
  {
    s_set.remove(this);
  }

  ... plus some other static method and/or property
      which accesses the set of all instances ...
};

Или просто природе использования ABC для реализации интерфейсов свойственно то, что они остаются пустыми, встроенными и защищенными?

Чаще всего они просто не объявляются вообще!Нет причин их объявлять:

  • Пустой и встроенный => зачем это объявлять?
  • Защищено => в ABC, вероятно, уже есть некоторые чистый виртуальный методы и, следовательно, уже не могут быть созданы, кроме как в качестве подкласса.

Другие советы

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

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

Как можно использовать конструктор абстрактного базового класса для чего-либо?

Предположим, у вас есть абстрактный базовый класс B и производный класс D. Когда создается объект типа D, сначала вызывается конструктор B, но в этот момент объект " is " тип B (см. здесь ) - в частности, вызов любых виртуальных функций из тела конструктора B вызовет собственные реализации B этих функций. Но если B является чисто абстрактным классом, ни одна из этих виртуальных функций не определена, поэтому программа немедленно завершит работу.

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

Помнить: «Получение ресурса — это инициализация».

Иногда мы используем абстрактные базовые классы в качестве своего рода механизма блокировки.Например, в многопоточной среде, где нескольким потокам необходимо совместно использовать один ресурс, поток может использовать конструктор как способ получения ресурса, а деструктор — для его освобождения.

void PlayWithPaintBallGun(Target &target)
{
    PaintBallGun paintBallGun;    // constructor waits until the gun is free,
                                  // then picks it up.

    paintBallGun.Aim(target);     // Shoot something
    paintBallGun.Fire();          //

                                  // Clever! The destructor is automatically
                                  // called when it goes out of scope. So we
                                  // can't forget to put the gun down.
}

Хьюго

Я не могу придумать много полезных примеров. Класс без данных-членов не имеет состояния и поэтому не может ничего инициализировать. Вы можете сделать так, чтобы конструктор / деструктор занялся ведением журнала для вас. Например, чтобы зарегистрировать создание / уничтожение всех объектов Visitor:

class Visitor {
public:
    Visitor() {
        std::cout << "Visitor@" << this << " created" 
                  << std::endl;
    }

    virtual ~Visitor() {
        std::cout << "Visitor@" << this << " destroyed" 
                  << std::endl;
    }

    virtual void visitA(A*) = 0;
    virtual void visitB(B*) = 0;
    // ...
};

обычно его инициализируют только члены с разумными ценностями.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top