Откуда “чистая виртуальная функция называет” катастрофические отказы прибывшими?

В Java все переменные, которые вы объявляете, на самом деле являются «ссылками» на объекты (или примитивы), а не самими объектами.

При попытке выполнить один метод объекта , ссылка просит живой объект выполнить этот метод. Но если ссылка ссылается на NULL (ничего, нуль, void, nada), то нет способа, которым метод будет выполнен. Тогда runtime сообщит вам об этом, выбросив исключение NullPointerException.

Ваша ссылка «указывает» на нуль, таким образом, «Null -> Pointer».

Объект живет в памяти виртуальной машины пространство и единственный способ доступа к нему - использовать ссылки this. Возьмем этот пример:

public class Some {
    private int id;
    public int getId(){
        return this.id;
    }
    public setId( int newId ) {
        this.id = newId;
    }
}

И в другом месте вашего кода:

Some reference = new Some();    // Point to a new object of type Some()
Some otherReference = null;     // Initiallly this points to NULL

reference.setId( 1 );           // Execute setId method, now private var id is 1

System.out.println( reference.getId() ); // Prints 1 to the console

otherReference = reference      // Now they both point to the only object.

reference = null;               // "reference" now point to null.

// But "otherReference" still point to the "real" object so this print 1 too...
System.out.println( otherReference.getId() );

// Guess what will happen
System.out.println( reference.getId() ); // :S Throws NullPointerException because "reference" is pointing to NULL remember...

Это важно знать - когда больше нет ссылок на объект (в пример выше, когда reference и otherReference оба указывают на null), тогда объект «недоступен». Мы не можем работать с ним, поэтому этот объект готов к сбору мусора, и в какой-то момент VM освободит память, используемую этим объектом, и выделит другую.

104
задан Wolf 11 June 2015 в 11:47
поделиться

5 ответов

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

(См. живую демонстрацию здесь )

class Base
{
public:
    Base() { doIt(); }  // DON'T DO THIS
    virtual void doIt() = 0;
};

void Base::doIt()
{
    std::cout<<"Is it fine to call pure virtual function from constructor?";
}

class Derived : public Base
{
    void doIt() {}
};

int main(void)
{
    Derived d;  // This will cause "pure virtual function call" error
}
106
ответ дан Destructor 24 November 2019 в 04:10
поделиться

А также стандартный случай вызывания виртуальной функции от конструктора или деструктора объекта с чистыми виртуальными функциями, можно также получить чистый вызов виртуальной функции (на MSVC, по крайней мере), если Вы вызываете виртуальную функцию после объекта, был уничтожен. Очевидно, это - довольно плохая вещь попытаться сделать, но если Вы работаете с абстрактными классами как интерфейсы, и Вы портите тогда, это - что-то, что Вы могли бы видеть. Возможно более вероятно, если Вы используете считаемые интерфейсы, на которые ссылаются, и Вы имеете касательно ошибки количества или если у Вас есть объектное состояние состязания разрушения использования/объекта в многопоточной программе... Вещь об этих видах purecall состоит в том, что часто менее легко постигнуть то, что продолжается как проверка на 'обычных подозреваемых' в виртуальных вызовах в ctor, и dtor подойдет чистый.

Для помощи с отладкой этих видов проблем, в различных версиях MSVC, можно заменить purecall обработчик библиотеки времени выполнения. Вы делаете это путем предоставления собственной функции эту подпись:

int __cdecl _purecall(void)

и соединение его перед соединением библиотеки времени выполнения. Это дает ВАМ контроль того, что происходит, когда purecall обнаруживается. Как только Вы имеете контроль, можно сделать что-то более полезное, чем стандартный обработчик. У меня есть обработчик, который может обеспечить отслеживание стека того, где purecall произошел; посмотрите здесь: http://www.lenholgate.com/blog/2006/01/purecall.html для получения дополнительной информации.

(Отмечают, можно также назвать _set_purecall_handler () для установки обработчика в некоторых версиях MSVC).

64
ответ дан Len Holgate 24 November 2019 в 04:10
поделиться

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

могут быть более "творческие" причины, также: возможно, Вам удалось отрезать часть Вашего объекта, где виртуальная функция была реализована. Но обычно это просто, что экземпляр был уже уничтожен.

7
ответ дан Braden 24 November 2019 в 04:10
поделиться

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

Чистое предположение

редактирование: похож, я неправ в рассматриваемом случае. OTOH IIRC некоторые языки действительно позволяет вызовы vtbl из деструктора конструктора.

0
ответ дан BCS 24 November 2019 в 04:10
поделиться

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

class A
{
  A *pThis;
  public:
  A()
   : pThis(this)
  {
  }

  void callFoo()
  {
    pThis->foo(); // call through the pThis ptr which was initialized in the constructor
  }

  virtual void foo() = 0;
};

class B : public A
{
public:
  virtual void foo()
  {
  }
};

B b();
b.callFoo();
-2
ответ дан 1800 INFORMATION 24 November 2019 в 04:10
поделиться
Другие вопросы по тегам:

Похожие вопросы: