Могу ли я установить условную точку останова в методе базового класса, которая запускается только в том случае, если это экземпляр определенного производного класса?

Скажем, у меня есть базовый класс A и два производных класса B и C. Класс A имеет некоторый метод, называемый f().

Есть ли способ установить условную точку останова в A:: f() в visual studio, которая будет ударяться только тогда, когда мой 'this' на самом деле является экземпляром класса C?

Например


    void A::f()
    {
    some code and a breakpoint 
    }

    void foo(A* a)
    {
       a->f();
    }

    void bar()
    {
       A a;
       B b;
       C c;
       foo(&a); // breakpoint isn't hit
       foo(&b); // breakpoint isn't hit
       foo(&c); // breakpoint is hit
    }

Мне удалось достичь этого, проверив указатель виртуальной таблицы в состоянии точки останова, но там должен быть лучший (более простой) способ.

Спасибо заранее.

EDIT: изменение исходного кода, как было предложено в комментариях, не является решением, которое я ищу. Это нужно делать только с помощью отладчика VС++.

Ответ 1

Вы можете. Прежде всего, определите адрес виртуальной таблицы типа, которую вы хотите проверить. Затем установите точку останова с условием типа   (arg).__ vfptr!= 0x01188298 где 0x01188298 - ваш адрес типа vtable. Что это.

Ответ 2

Это для dynamic_cast.

void A::f() {
    ...
    if (dynamic_cast<C*>(this)) {
        __debugbreak();
    }
    ...
}

Если вам нужно сделать это отладчиком, вам придется сломать, проверьте тип с помощью dynamic_cast в окне Immediate, а затем продолжите, если нет.

Ответ 3

Эта публикация, похоже, указывает на возможность программной отладки в Visual Studio.

В качестве альтернативы, если вы можете скомпилировать источник в gcc или каким-то образом использовать gdb, вы можете воспользоваться функциональностью сценариев python для создания сложных условных точек останова.

Вот некоторые руководства по python для gdb. Вот соответствующая документация gdb.

Ответ 4

На сайте вызова (т.е. когда выполняется вызов foo), сделать это практически невозможно. В самой функции вы можете сделать это, имея виртуальную функцию, одна из которых вернет true. Все остальные вернутся false. Если функция возвращает true, вы можете вызвать функцию DebugBreak. Или поместите его возвращаемое значение в некоторую переменную bool и установите условную точку останова. Да, конечно, для этого требуется, чтобы виртуальная функция была добавлена ​​во всех классах (или некоторых). Кроме того, вы можете иметь одну простую переменную bool в базовом классе, которая будет назначаться производным классом. Соответствующий производный класс (C в вашем случае) может назначить его как true. Вы можете делать этот виртуальный/переменный материал в режиме отладки только с помощью макроса _DEBUG.

Другое решение - иметь макрос, который вызывает функцию foo. Для реализации требуется виртуальная функция/член-переменная в базовом классе, как описано выше, но foo не будет изменена.

#define CALL_FOO(obj) \
  if(obj->member_variable_test) DebugBreak(); \
  foo(&obj);

И вызовите CALL_FOO вместо foo:

CALL_FOO(&c); // breakpoint is hit

Хотя, возможно, это неприемлемо, но работает. И точка останова попадает именно туда, где вам нужно! Вы можете заставить этот макрос работать только в debug-build.