Проблема понимая 'виртуальный' C++

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

, Если Ваш не знакомый с использованием основанного на Eclipse IDE, GUI возьмет немного привыкающее к. Однако, как только Вы добираетесь для понимания идей GUI, которые уникальны для Eclipse (например, перспектива), использование инструмента становится хорошим опытом.

инструменты CDT обеспечивают достойный индексатор C/C++, который позволяет Вам быстро находить ссылки на методы в Вашей кодовой базе. Это также обеспечивает хороший инструмент макрорасширения и ограниченную поддержку рефакторинга.

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

Для получения дополнительной информации об отладке использования CDT Eclipse, можно хотеть проверить эти руководства:

по Отладке MI CDT

5
задан Mike 1 December 2009 в 21:35
поделиться

9 ответов

Внесите следующие изменения, и вы поймете, почему:

#include <iostream>

using namespace std;

class A {
    public:
        int a();
};

int A::a() {
    return 1;   
}

class B : public A { // Notice public added here
    public:
        int a();
};

int B::a() {
    return 2;
}

int main() {
    A* b = new B(); // Notice we are using a base class pointer here
    cout << b->a() << endl; // This will print 1 instead of 2
    delete b; // Added delete to free b
    return 0;
}

Теперь, чтобы заставить его работать так, как вы планировали:

#include <iostream>

using namespace std;

class A {
    public:
        virtual int a(); // Notice virtual added here
};

int A::a() {
    return 1;   
}

class B : public A { // Notice public added here
    public:
        virtual int a(); // Notice virtual added here, but not necessary in C++
};

int B::a() {
    return 2;
}

int main() {
    A* b = new B(); // Notice we are using a base class pointer here
    cout << b->a() << endl; // This will print 2 as intended
    delete b; // Added delete to free b
    return 0;
}

Замечание, которое вы добавили о виртуальных деструкторах, совершенно верно. В вашем примере нет ничего, что нужно было бы очистить, но скажите, что и у A, и у B есть деструкторы. Если они не отмечены как виртуальные, какой из них будет вызываться с указателем базового класса? Подсказка: он будет работать точно так же, как метод a (), когда он не был помечен как виртуальный.

16
ответ дан 18 December 2019 в 05:40
поделиться

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

2
ответ дан 18 December 2019 в 05:40
поделиться

Вы можете думать об этом следующим образом:

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

С другой стороны, в C ++ он не обязательно будет вызываться.

Если у вас есть базовый класс Base и производный класс Derived, и в них обоих есть невиртуальная функция с именем 'foo', тогда

Base * base;
Derived *derived;

base->foo(); // calls Base::foo
derived->foo(); // calls Derived::foo

Если foo виртуальный, то оба вызовите Derived :: foo.

9
ответ дан 18 December 2019 в 05:40
поделиться

So virtual also tells the compiler to call up the parent's destructors? This seems to be very different from my original understanding of virtual as "make the function overridable"

Your original and your new understanding are both wrong.

  • Methods (you call them functions) are always overridable. No matter if virtual, pure, nonvirtual or something.
  • Parent destructors are always called. As are the constructors.

"Virtual" does only make a difference if you call a method trough a pointer of type pointer-to-baseclass. Since in your example you don't use pointers at all, virtual doesn't make a difference at all.

If you use a variable a of type pointer-to-A, that is A* a;, you can not only assign other variables of type pointer-to-A to it, but also variables of type pointer-to-B, because B is derived from A.

A* a; 
B* b;

b = new B(); // create a object of type B. 
a = b;       // this is valid code. a has still the type pointer-to-A, 
             // but the value it holds is b, a pointer to a B object.

a.a();       // now here is the difference. If a() is non-virtual, A::a()
             // will be called, because a is of type pointer-to-A. 
             // Whether the object it points to is of type A, B or
             // something entirely different doesn't matter, what gets called
             // is determined during compile time from the type of a.

a.a();       // now if a() is virtual, B::a() will be called, the compiler
             // looks during runtime at the value of a, sees that it points
             // to a B object and uses B::a(). What gets called is determined
             // from the type of the __value__ of a.
2
ответ дан 18 December 2019 в 05:40
поделиться

Как вы можете видеть ниже, функция A :: a успешно заменена на B :: a без необходимости virtual

Это может или не может работать. В вашем примере это работает, но это потому, что вы создаете и используете объект B напрямую, а не через указатель на A . См. C ++ FAQ Lite, 20.3 .

Значит, virtual также сообщает компилятору вызывать деструкторы родителя?

Виртуальный деструктор необходим, если вы удаляете указатель базового класса, указывающий на объект производный класс и ожидайте запуска как базового, так и производного деструкторов. См. C ++ FAQ Lite, 20.7 .

1
ответ дан 18 December 2019 в 05:40
поделиться

Вам понадобится виртуальная машина, если вы используете указатель базового класса, как это сказано в consultutah (и других, пока я печатаю;)).

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

Виртуальный деструктор особенно важен, потому что производные классы могут объявлять другие переменные в куче (например, используя ключевое слово 'new'), и вам нужно

Однако вы можете заметить, что в C ++ вы, как правило, используете меньше наследований, чем, например, в java (вы часто используете шаблоны для аналогичного использования), и, возможно, вы даже не используете нужно беспокоиться об этом. Кроме того, если вы никогда не объявляете свои объекты в куче ("A a;" вместо "

1
ответ дан 18 December 2019 в 05:40
поделиться

Попробуйте ((A *) & b) .a () и посмотрите, что тогда вызывается.

Ключевое слово virtual позволяет вам обрабатывать объект абстрактным способом (IE через базовый класс указатель) и все же вызывать код потомка ...

Другими словами, виртуальное ключевое слово «позволяет старому коду вызывать новый код». Возможно, вы написали код для работы с A, но через виртуальные функции этот код может вызывать более новую функцию B a ().

0
ответ дан 18 December 2019 в 05:40
поделиться

Допустим, вы создали экземпляр B, но сохранили его как экземпляр A:

A *a = new B();

и вызвали функцию a (), чья реализация a () будет вызываться?

Если a () не виртуальный A будет называться. Если бы a () был виртуальным, созданная версия подкласса a () вызывалась бы независимо от того, как вы его держите.

Если конструктор B выделил тонны памяти для массивов или открытых файлов, вызов

delete a;

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

Кстати, хороший вопрос.

0
ответ дан 18 December 2019 в 05:40
поделиться

I always think about it like chess pieces (my first experiment with OO).

A chessboard holds pointers to all the pieces. Empty squares are NULL pointers. But all it knows is that each pointer points a a chess piece. The board does not need to know more information. But when a piece is moved the board does not know it is a valid move as each pice has different characteristica about how it moves. So the board needs to check with the piece if the move is valid.

Piece*    board[8][8];

CheckMove(Point const& from,Point const& too)
{
    Piece*  piece = board[from.x][from.y];
    if (piece != NULL)
    {
        if (!piece->checkValidMove(from,too))
        {    throw std::exception("Bad Move");
        }
        // Other checks.
    }
}

class Piece
{
    virtual bool checkValidMove(Point const& from,Point const& too)  = 0;
};

class Queen: public Piece
{
    virtual bool checkValidMove(Point const& from,Point const& too) 
    {
         if (CheckHorizontalMove(from,too) || CheckVerticalMoce(from,too) || CheckDiagonalMove(from,too))
         {
             .....
         }
    }
}
0
ответ дан 18 December 2019 в 05:40
поделиться
Другие вопросы по тегам:

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