Как будет работать этот код C ++?

0

Вот немного кода:

======================
[Player.cpp]
======================
#include "TmTeam.h"
#include "TmPlayer.h"
#include "Player.h"

void Player::doTurn()
{
    (...)
    Tm_doPost();
    (...)
} 

===================
[Player.h]
===================
class Player
{
    (...)
public:
    (...)
    virtual void Tm_doPost() = 0;
    (...)
}; 

===================
[TmPlayer.cpp]
===================
#include "TmPlayer.h"
#include "TmTeam.h"

void TmPlayer::Tm_doPost()
{
    (...)
} 

===================
[TmPlayer.h]
===================
#include "Player.h"
class TmPlayer : public Player
{
public:
    (...)
    void Tm_doPost();
    (...)
}; 

===================
[Team.cpp]
===================
#include "TmTeam.h"
#include "TmPlayer.h"
#include "Team.h"

void Team::doTurn()
{
    (...)
    Tm_doPost();
} 

===================
[Team.h]
===================
class Team
{
    (...)
public:
    (...)
    virtual void Tm_doPost() = 0;
    (...)
}; 

===================
[TmTeam.cpp]
=================== 
#include "TmTeam.h"
#include "TmPlayer.h"

void TmTeam::Tm_doPost()
{
    (...)
} 

===================
[TmTeam.h]
===================
#include "Team.h"
class TmTeam : public Team
{
    (...)
public:
    (...)
    void Tm_doPost();
    (...)
}; 

Мне интересно, какая реализация Tm_doPost() будет выполняться в обоих вызовах, которые показаны здесь... Я полагаю, что тот, что в Team.cpp будет использовать определение, предоставленное TmTeam.cpp (пожалуйста, исправьте меня, если я ошибаюсь), но как насчет вызова, сделанного в Player.cpp? Использует ли это определение в TmPlayer.cpp или просто вернет 0, как это говорит в Player.h? И как в Player.h, так и в Team.h, что там делает ключевое слово virtual?

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

  • 0
    Всегда глава объектов? Я думаю, что вы беспокоитесь о типах файлов (.cpp / .h), ищите иерархию классов и создаваемые им объекты.
  • 0
    Я думаю, что ни один из звонков не действителен? Когда вы вызываете функцию в функции-члене Team, компилятор будет искать чисто виртуальную функцию, объявленную в Team. Поправьте меня, если я ошибаюсь, но я считаю, что это будет ошибкой компоновщика.
Показать ещё 4 комментария
Теги:
inheritance
virtual-functions

3 ответа

1
Лучший ответ

Я постараюсь ответить на ваши вопросы, поэтому, чтобы быть ясным, я процитировал часть вашего вопроса, на который я отвечаю.

Ваш вопрос 1: Мне интересно, какая реализация Tm_doPost() будет выполняться в обоих вызовах, которые показаны здесь... Предполагаю, что в Team.cpp будет использоваться определение, предоставленное TmTeam.cpp (пожалуйста, исправьте меня, если Я не прав),

Я думаю, что ваша формулировка делает его вводящим в заблуждение. Понимаете, вы не можете создать экземпляр объекта "Команда", потому что он не реализует виртуальную функцию "Tm_doPost()". Если вы посмотрите файл Team.cpp, то он реализует команду Team :: doTurn().

Однако подкласс класса " Team " "TmTeam" реализует виртуальную функцию "Tm_doPost()", поэтому ее можно создать.

У вас может быть список "Team ", который содержит много экземпляров "TmTeam". Фактически, любой суперкласс может использоваться как основное имя класса для подклассов. Он назывался " полиморфизм ". пример:

List<Team> myList = new List<Team>();
myList.push_back(new TmTeam());
myList.push_back(new TmTeam());
myList.push_back(new TmTeam2()); // <--- if you have a class like this:  " class TmTeam2 : Team"
//Notice there mixed items on a list of "Team"s, because each item shares the same parent class.

Теперь, если бы мы сделали этот код:

 //pseudocode, iterating through each item in myList, giving it the variable name "x"
for (each Team, x, in myList)
{
    x.Tm_doPost();
}

Какая реализация Tm_doPost() будет выполнена? Будет ли это в TmTeam.cpp? Не обязательно. Объекты TmTeam в myList будут использовать эту функцию, но объект TmTeam2 будет использовать свое определение. У вас может быть много подклассов, и каждый подкласс должен реализовывать виртуальные функции, чтобы он мог быть создан. Всякий раз, когда он находится в списке объектов Team, компилятор задается вопросом: "Мне нужно вызвать" Tm_doPost() ", но я не уверен, какой из подклассов это. Это TmTeam или TmTeam2? Тем не менее, это не нужно удивляться, потому что C++ спроектирован так, что он выясняет, что такое объект на самом деле, будь то TmTeam или TmTeam2. Затем он вызывает функцию объекта TmTeam, которая, естественно, использует определение этой функции в своих определениях классов. TmTeam2 будет использовать свое определение. Так же, как ожидается нормальное поведение C++.

Таким образом, поскольку в Team.cpp "Tm_doPost()" является виртуальным, ему нужно будет выяснить, что является фактическим (мгновенным) объектом, а затем вызвать его реализацию "Tm_doPost()".

Ваш вопрос 2: но как насчет вызова в Player.cpp? Будет ли оно использовать определение, которое в TmPlayer.cpp,

Это зависит. Поскольку Player не может быть экземпляром объекта, тогда, когда на нем сделаны вызовы (как будто есть список игроков, как, например, пример выше), он должен выяснить, что представляет собой объект ДЕЙСТВИТЕЛЬНО, - который будет некоторым подклассом Игрок. Если подкласс является TmPlayer, он будет вызывать реализацию класса TmPlayer класса Tm_doPost():

void TmPlayer::Tm_doPost()

Однако, если это будет другой (теоретический) подкласс Player, такой как "TmPlayer2", тогда он будет вызывать его реализацию Tm_doPost():

void TmPlayer2::Tm_doPost()

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

Ваш вопрос 3: или просто вернет 0, как говорится в Player.h?

В Player.h строка, о которой я думаю, вы имеете в виду:

virtual void Tm_doPost() = 0;

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

Синтаксис мог бы быть

virtual void Tm_doPost() ~ $;

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

Ваш вопрос 4: И как в Player.h, так и в Team.h, что там делает ключевое слово virtual?

Это делает так, что всякий раз, когда вызывается эта функция, она будет искать то, что представляет собой реальная функция объекта экземпляра, и выполнить это. Это также делает так, что любые подклассы могут выбрать переопределение функции, объявив другую функцию с тем же именем. Но они также могут отказаться от переопределения, а затем вместо этого можно использовать функцию по умолчанию родительского класса. (Это если нет синтаксиса "= 0;" - если это не чистая виртуальная функция.) Если это чистая виртуальная функция, и вы не переопределяете ее в подклассе, то этот подкласс также не может быть создан, и его подкласс может быть создан только при его переопределении.

Заключительные комментарии и рекомендации:

Это мое лучшее понимание в момент виртуальных функций, но я очень рекомендую всю главу 12 этого сайта: http://www.learncpp.com/cpp-tutorial/122-virtual-functions/ Именно там я узнал, что Я знаю. Я честно обнаружил, что лучший способ для меня изучить виртуальные функции - следить за онлайн-учебниками, а также делать небольшие эксперименты с практическими программами, создавать кучу классов, некоторые из которых унаследованы от других и имеют разные функции, а затем я должен найти какая функция была выполнена, в зависимости от того, что она напечатала на терминале.

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

0

Когда вы вызываете такую функцию,

void Player::doTurn()
{
    //...
    Tm_doPost();
    //...
}

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

Я не знаю, что делает ваш код, но поскольку у вас есть Team, Player и класс TeampPlayer, я предполагаю, что вы пытаетесь объединить игроков в команде и добиться полиморфизма с вызовом tm_doPost()? Это способ сделать это

#include <iostream>
struct player{
    virtual void foo(void){std::cout<<"player::foo";}
};
struct teamPlayer: public player{
    virtual void foo(void){std::cout<<"teamPlayer::foo";}
};

тогда, когда у вас будет динамическое связывание с функцией foo;

int main(int argc, char** argv){
     teamPlayer t;
     player* p = &t;
     p->foo(); //outputs "teamPlayer::foo"
     return 0;
}
0

Функции, объявленные как

virtual void Tm_doPost() = 0;

не возвращать 0. Они являются чисто виртуальными и определяют интерфейс класса. Оба подклассы вы спрашиваете о будет называть их методами предков и Player::doTurn() метод будут вызывать текущий объект Tm_doPost() метод.

Функции-члены, объявленные с помощью virtual ключевого слова, вызываются с помощью таблицы виртуальных методов объекта. Поэтому, когда объект класса создается, все виртуальные методы вызывается путем ссылки на адреса, хранящиеся в таблице. Поэтому для суперкласса Player не требуется знать метод Tm_doPost.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню