виртуальные разрушители против обычных методов в C ++ - PullRequest
0 голосов
/ 14 мая 2018

Рассмотрим следующие три программы на C ++:

программа 1

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived();
};

derived::~derived(){}

int main(){}

программа 2

struct base{
  virtual ~base() =0;
};

struct derived: public base{
  ~derived(){}
};

int main(){}

программа 3

struct base{
  virtual void func() =0;
};

struct derived: public base{
  void func();
};

void derived::func(){}

int main(){}

Программы # 2 и # 3 компилируются и работают нормально, однако первая выдает следующую ошибку:

Undefined symbols for architecture x86_64:
  "base::~base()", referenced from:
    derived::~derived() in main-d923b9.o
ls: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Я хотел бы знать, почему я не могу определить виртуальные деструкторы вне определения класса, однако я могу сделать это внутри определения класса. Кроме того, я могу определять методы вне класса, но не деструкторы.

Ответы [ 2 ]

0 голосов
/ 14 мая 2018

Ответ о том, почему программа 2 строит, заключается в том, как работает ссылка. Когда определение функции находится за пределами объявления класса, компоновщик должен создать тело функции в конечном двоичном файле, поэтому ему также необходимо иметь определение ~ base ().

Если вы введете случай 2 derived d; в основное тело, вы получите ту же ошибку, что и в случае 1, так как компоновщик должен будет создать определения производных функций-членов и потребуется тело ~ base (), как в случае 1.

0 голосов
/ 14 мая 2018

Это неправильно

struct base{
  virtual ~base() =0;
};

потому что base::~base не определено. Несмотря на то, что он был объявлен как чисто виртуальный, его необходимо определить (вне класса, нет синтаксического способа объявить функцию как чисто виртуальную и определить ее как встроенную), поэтому derived может наследовать от нее:

struct base
{
    virtual ~base() = 0;
};

base::~base() {}

Я хотел бы знать, почему я не могу определить виртуальные деструкторы вне определения класса

Ну, вы можете: я только что сделал.


Тогда зачем вам нужно реализовывать функцию (~base), которая была объявлена ​​чисто виртуальной?

Поскольку derived наследуется от base, когда объект типа derived разрушается, он обязательно вызывает деструктор base. Вот как работает наследование. В некотором смысле, derived::~derived необходимо связать с base::~base. Хотя base::~base является чисто виртуальным (то есть класс, наследующий от base, не является полным типом, если он не определяет деструктор), ему необходимо определить , чтобы ~derived нашел его и компоновщик стал счастливый.

...