Это работало на меня (в Windows Subsystem для Linux, Ubuntu):
npm install puppeteer
sudo apt-get install gconf-service libasound2 libatk1.0-0 libatk-bridge2.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 ca-certificates fonts-liberation libappindicator1 libnss3 lsb-release xdg-utils wget
список Зависимости от: https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md#chrome-headless-doesnt-launch-on-unix
Если вы объявляете виртуальные функции, вы также должны объявить свой деструктор виртуальным; -).
B имеет виртуальную таблицу, потому что у нее есть виртуальная функция, а именно func0 ()
. Если вы объявляете функцию (включая деструктор) виртуальной в базовом классе, все его производные классы также будут иметь функцию с такой же виртуальной подписью. И это приведет к тому, что у них будет vtable. Более того, B будет иметь vtable, даже если вы не объявили в ней func0
явно.
Не виртуальные функции не упоминаются через vtables.
См. 2.
Нет. Таблицы классов создаются на основе объявлений классов. Тела функций класса (не говоря уже о других функциях) не учитываются. Следовательно, B имеет vtable, потому что его функция func0 ()
виртуальная.
Есть еще одна хитрая деталь, хотя не в этом суть вашего вопроса. Вы объявили свою функцию B :: func0 ()
встроенной. В компиляторе gcc
, если виртуальная функция объявлена встроенной, она сохраняет свой слот в виртуальной таблице, причем слот указывает на специальную функцию, созданную для этой встроенной (которая считается принятием ее адреса, что делает встроенную испускается). Это означает, что то, является ли функция встроенной, не влияет на количество слотов в vtable и ее необходимость в классе.
Да, потому что его базовый класс имеет один; также его деструктор является виртуальным (даже если вы не объявили его виртуальным), потому что деструктор базового класса является виртуальным.
Нет
Нет.
Нет. На самом деле я не думаю, что текущий код является законным: компилятор вызовет деструктор A после того, как он вызовет деструктор B, даже если вы явно не вызываете ~ A из ~ B; поэтому я не думаю, что вам следует вызывать ~ A из ~ B, даже если компилятор позволяет вам.
Ссылаясь на обновленный пример:
Несколько дополнительных примечаний (зависит от компилятора, но это довольно распространенные обобщения):