Domanda

Here's a bit of code:

======================
[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();
    (...)
}; 

I'm wondering which implementation of Tm_doPost() will execute in both the calls that are shown here... I presume that the one in Team.cpp will use the definition provided by TmTeam.cpp (please correct me if I'm wrong), but what about the call made in Player.cpp? Will it use the definition that's in TmPlayer.cpp, or will just return 0 like it says in Player.h? And in both Player.h and Team.h, what does the keyword virtual does there?

By the way I tried to be as accurate as possible with the includes on top of each block of code, in case it's relevant to the question...

È stato utile?

Soluzione

I will try my best to answer your questions, so to be clear I quoted the part of your question that I'm answering.

Your Question 1: I'm wondering which implementation of Tm_doPost() will execute in both the calls that are shown here... I presume that the one in Team.cpp will use the definition provided by TmTeam.cpp (please correct me if I'm wrong),

I think your wording is making it misleading. You see, you can't make an instance of a "Team" object, because it does not implement the virtual function "Tm_doPost()". If you look at the Team.cpp file, that it only implements Team::doTurn().

However, the class "Team"'s subclass "TmTeam" does implement the virtual function "Tm_doPost()", so it can be instantiated.

You could have a list of "Team"s, which contains many "TmTeam" instances. In fact, any superclass can be used as a overarching class name for the subclasses. It's called "polymorphism." example:

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's mixed items on a list of "Team"s, because each item shares the same parent class.

Now, if we did this code:

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

Which implementation of Tm_doPost() will be executed? Will it be the one in TmTeam.cpp? Not necessarily. The TmTeam objects in myList will use that function, but the TmTeam2 object will use its definition. You can have many subclasses, and each subclass must implement the virtual functions for it to be able to be instantiated. Whenever it is in a list of Team objects, the compiler wonders: 'I need to call "Tm_doPost()" but I'm not sure which subclass this is. Is it a TmTeam or a TmTeam2?' However, it doesn't need to wonder, because C++ is designed that it finds out what the object really is, whether it's TmTeam or TmTeam2. Then, it calls the function on the TmTeam object, which naturally uses the definition of that function within its own class definitions. TmTeam2 will use its definition. Just like normal C++ behavior is expected to work.

So, since in Team.cpp, "Tm_doPost()" is virtual, it will have to find out what is the actual (instantiatable) object is and then call its implementation of "Tm_doPost()."

Your Question 2: but what about the call made in Player.cpp? Will it use the definition that's in TmPlayer.cpp,

It depends. Since Player is not able to be an instantiated object, then when calls are made on it (as if there is a list of Players, like the example above), it must find out what the object REALLY is - which will be some subclass of Player. If the subclass happens to be TmPlayer, then it will call TmPlayer class's implementation of Tm_doPost():

void TmPlayer::Tm_doPost()

However, if it happens to be another (theoretical) subclass of Player, such as "TmPlayer2", then it will call its implementation of Tm_doPost():

void TmPlayer2::Tm_doPost()

You see, the method that is called really depends on what the actual instance class is.

Your Question 3: or will just return 0 like it says in Player.h?

In Player.h, the line I think you are referring to:

virtual void Tm_doPost() = 0;

does not mean that it will return anything. It is just some syntax that tells the compiler that this function will not be implemented in this class - only the subclasses will be allowed to implement it.

The syntax could have been

virtual void Tm_doPost() ~ $;

and get the job done still - there's not special meaning to it. I guess a nice way to look at it, is to say that this function's implementations in this class equals 0 (or, none).

Your Question 4: And in both Player.h and Team.h, what does the keyword virtual does there?

It makes it so whenever that function is called, it will look up what the instance object's real function is, and execute that. It also makes it so any subclasses can choose to override the function by declaring another function with the same name. But, they can also choose not to override it, and then the parent class's default function can be used instead. (This is if there is no "=0;" syntax - if it's not a pure virtual function.) If it is a pure virtual function and you do not override it in a subclass, then that subclass cannot be instantiated either, and its subclass can only be instantiated if it overrides it.

Final comments & recommendations:

This is my best understanding at the moment of virtual functions, but I highly recommend the whole Chapter 12 of this site: http://www.learncpp.com/cpp-tutorial/122-virtual-functions/ It is where I learned what I know. I honestly found that the best way for me to learn virtual functions was to follow online tutorials while also doing little practice-program experiments, making a bunch of classes, some which inherited from others, and had different functions, and then I got to find out which function got executed, depending on what it printed to the terminal.

Then of course, using stack overflow along the way helps for bug-related issues.

Altri suggerimenti

The functions declared as

virtual void Tm_doPost() = 0;

don't return 0. They are purely virtual, and define the interface of the class. Both subclasses you're asking about will call their ancestors methods and the Player::doTurn() method will call current object's Tm_doPost() method.

Member functions declared with virtual keyword are called using object's virtual methods table. So when an object of a class is instantiated all virtual methods are called by referencing the addresses stored in the table. That's why the superclass Player doesn't need to know the implementation of the Tm_doPost method.

When you call a function like this,

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

i.e. within the member function of the class Player, the compiler should look for the function in that class, which in this case happens to be a pure virtual function without definition, so you can't call it. This name lookup business hardly has anything to do with files.

I don't know what your code does, but since you have a Team, a Player and a TeampPlayer class, I assume you're trying to aggregate players in a team and achieve polymorphism with the call to tm_doPost()? This is the way to do it

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

then when you'll have dynamic binding with the function foo;

int main(int argc, char** argv){
     teamPlayer t;
     player* p = &t;
     p->foo(); //outputs "teamPlayer::foo"
     return 0;
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top