Why is my virtual method being skipped over in C++? - c++

Long story short: The program I'm working on is a rogue like - even though that isn't really needed for this question.
Here's the hierarchy tree for my classes related to this question:
Entity
Item Creature
Weapon Armor
I have several virtual functions declared in Entity, which are also virtual in the classes derived from it.
I'm not sure how to word my question, but I'll explain the problem and post the code below. I have a factory type class, called ItemFactory, that opens an xml file and uses a simple parser that I made - and creates Item objects and sets their values. It has a method that returns an Item pointer. In my main file, I declare/define an ItemFactory object. When an Item needs to be dropped in the game, I use a pointer, that is of type, Item,
and call the method to randomly choose an Item to point to. All of this works perfectly..
Here's the problem. Entity has a virtual method called dumpObject() which prints the state of the variables it has. dumpObject() is also virtual in Item. When it's called from an Item, the method first calls Entity's dump with this:
Entity::dumpObject();
Then it dumps it's own variables.. I do the same for Weapon and Armor except using this:
Item::dumpObject();
My Question:
Since the ItemFactory holds both - Weapons and Armor, and the pointer in the main program points to an Item, shouldn't calling "itemPointer->dumpObject();" dump the values for Weapon/Armor (depending which it is pointing to..) which would also dump the values in Item which would also dump the values in Entity?
When I run the code, the only part that gets dumped is the part in Item and Entity.
Let me know if I need to provide more detail. Any suggestions? Thanks!
Here's the Code Snippets
I have the headers included, just tried to minimize the amount of code that I'm posting
Item.cpp
void Item::dumpObject(){
cout << "Item:" << endl;
dumpObjectData();
}
void Item::dumpObjectData(){
Entity::dumpObjectData();
cout << " [Weight] " << getWeight() << endl;
cout << " [Value] " << getValue() << endl;
cout << " [Quantity] " << getQuantity() << endl;
cout << " [Enchantment] " << getEnchantment() << endl;
}
Entity.cpp
void Entity::dumpObject(){
cout << "Entity:" << endl;
dumpObjectData();
}
void Entity::dumpObjectData(){
XMLSerializable::dumpObjectData(); //XMLSerialization handles parsing
cout << " [Name] " << getName() << endl;
cout << " [DisplayChar] " << getDisplayChar() << endl;
cout << " [Properties] " << endl;
for( auto it = m_vProperties.begin(); it != m_vProperties.end();it++ ){
cout << " - " << (*it) << endl;
}
}
Weapon.cpp
void Weapon::dumpObject(){
cout << "Weapon:" << endl;
dumpObjectData();
}
void Weapon::dumpObjectData(){
Item::dumpObjectData();
cout << " [Damage] " << getDamage() << endl;
cout << " [Range] " << getRange() << endl;
cout << " [Accuracy] " << getAccuracy() << endl;
cout << " [AmmoType] " << getAmmoType() << endl;
cout << " [Type] " << getType() << endl;
}
Armor.cpp
void Armor::dumpObject(){
cout << "Armor:" << endl;
dumpObjectData();
}
void Armor::dumpObjectData(){
cout << "calls to dump item data"<<endl;
Item::dumpObjectData();
cout << "calls to dump armor"<<endl;
cout << " [Type] " << getType() << endl;
cout << " [Slot] " << getSlot() << endl;
cout << " [ArmorValue] " << getArmorValue() << endl;
}
Main
ItemFactory myItems = ItemFactory::instance();
Item * pItem1 = myItems.generateItem();
pItem1->dumpObject();
Headers
Entity.h
#include "XMLSerializable.h"
#include <vector>
class Entity : public XMLSerializable {
public:
Entity(void);
virtual ~Entity(void);
virtual void dumpObject();
virtual void dumpObjectData();
};
Item.h
#include "Entity.h"
class Item : public Entity{
public:
Item(void);
virtual ~Item(void);
virtual void dumpObject();
virtual void dumpObjectData();
};
Weapon.h
#include "Item.h"
class Weapon : public Item {
public:
Weapon(void);
virtual ~Weapon(void);
virtual void dumpObject();
virtual void dumpObjectData();
};
Armor.h
#include "Item.h"
class Armor : public Item {
public:
Armor(void);
virtual ~Armor(void);
virtual void dumpObject();
virtual void dumpObjectData();
};
ItemFactory.cpp
ItemFactory & ItemFactory::instance(){
static ItemFactory myObj;
return myObj;
}
ItemFactory::ItemFactory(){
m_mtRandom.seed( time(NULL) );
fstream xmlFile;
xmlFile.open("items.xml");
vector<XMLSerializable*> pObjects;
parseXML(xmlFile, pObjects);
XMLSerializable * pObject;
for(auto it = pObjects.begin(); it != pObjects.end(); it++){
pObject = (*it);
Item * pItem = dynamic_cast<Item*>(pObject);
if (pItem != NULL){
m_vItems.push_back(pItem);
}
}
}
ItemFactory::~ItemFactory(){
}
Item * ItemFactory::generateItem() {
vector<Item*> tempItems;
for(auto it = m_vItems.begin(); it != m_vItems.end(); it++){
tempItems.push_back((*it));
}
int randomItem = (m_mtRandom() % (m_vItems.size() - 1));
Item * pItem = tempItems.at(randomItem);
Item * pReturnValue = new Item(*pItem);
return pReturnValue;
}
Now that I just did all that work, I don't think any of the code except maybe Main was necessary.. Lol I'm guessing my logic for the pointer in Main is wrong?

Well here's your problem:
Item * pReturnValue = new Item(*pItem);
This is giving you a shallow copy so that you do not get an Armor or Weapon.
If you need to do a copy given only a base class instance, define a clone method in the base class.
It looks like you are trying to use the prototype pattern, so you do want to create new instances?
class Entity : public XMLSerializable {
public:
Entity(void);
virtual ~Entity(void);
virtual Entity* clone() const { return new Entity(*this);}
virtual void dumpObject();
virtual void dumpObjectData();
};
class Armor : public Item {
public:
Armor(void);
virtual ~Armor(void);
virtual Armor* clone() const { return new Armor (*this);}
virtual void dumpObject();
virtual void dumpObjectData();
};
Note the use of covariant return values for clone(). I.e. The return values do differ but as the method signature matches and the return values are derived from one another, the call is virtual.
You then can write:
Item * pReturnValue = pItem->clone();
See: Wikipedia for background on the Prototype pattern.

Related

I can't access to the protected member of my base class

I am new at programming using c++ and having some troubles creating my constructors & objects.
How can I access to my protected members like int p_iID in the Fahrzeug class?
I have to access them for both of my objects seperately.
I would be so happy if you could help me out with this.
class Fahrzeug {
private:
protected:
string p_sName;
int p_iID;
double p_dMaxGeschwindigkeit;
double p_dGesamtStrecke;
double p_dGesamtZeit;
double p_dZeit;
public:
virtual void vAusgeben(Fahrzeug* pFahrzeug1,Fahrzeug* pFahrzeug2);
virtual void vKopf();
virtual void vSimulieren(Fahrzeug *pFahrzeug, Fahrzeug *pFahrzeug2);
class PKW;
class PKW: public Fahrzeug{
PKW(const int p_iMaxID, string p_sName, double p_dMaxGeschwindigkeit, double p_dGesamtStrecke) {
p_iID = p_iMaxID;
this->p_sName = p_sName;
this->p_dMaxGeschwindigkeit = (p_dMaxGeschwindigkeit < 0) ? 0 : p_dMaxGeschwindigkeit;
this->p_dGesamtStrecke = p_dGesamtStrecke;
}
void vAusgeben(PKW pkw1, PKW pkw2) {
cout << "\n";
PKW pkw1;
PKW pkw2;
pkw1.vKopf();
cout << setw(5) << left << pkw1.p_iID<< " " << setw(10) <<pkw1.p_sName << setw(8) << " " << setw(15) << showpoint << pkw1.p_dMaxGeschwindigkeit << setw(3) << " " << pkw1.p_dGesamtStrecke; //Here I have the issue with pkw1.p_sName
cout << "\n";
cout << setw(5) << left << pkw2.p_iID << " " << setw(10) << pkw2.p_sName << setw(8) << " " << setw(15) << showpoint << pkw2.p_dMaxGeschwindigkeit << setw(3) << " " << pkw2.p_dGesamtStrecke;
cout << "\n";
}
}
void vAusgeben(PKW pkw1, PKW pkw2) {
You probably don't want to pass your PKW objects by value (or expect object slicing). Pass const references instead:
void vAusgeben(const PKW& pkw1, const PKW& pkw2) {
Also, why are you shadowing your 2 parameters with these local variables?
PKW pkw1; // ???
PKW pkw2; // ???
Aside from the issues raised in comments (and in another answer), there's a special rule for protected members that sometimes surprises people. An object of a derived type can access protected members of its base sub-object, but it can't access protected members of some other object. So:
struct B {
protected:
int i;
};
struct D : B {
void f(const B&);
};
void D::f(const B& b) {
i = 3; // okay, accessing my own protected member
b.i = 3; // no, access to protected member of different object not allowed
}
In the code in the question, the function PKW::vAusgeben can access its own copies of p_sName, p_dMaxGeschwindigkeit, and p_dGesamtStrecke, but it can't access pkw1.p_sName, pkw1.p_dMaxGeschwindigkeit, or pkw1.p_dGesamtStrecke.

C++ sample Observer Template Class error

I am creating observer template sample in C++ on windows.
Here there is an agent which has a list of customers. Whenever an entity(variable x) of the agent changes it notifies its customers about the same and passes the value of x to customers. The customers then store this value in their respective variables.
In the below code the agent acts as subject and the customers act as observers.
The agents are created from their agent template class and the customers are created from their customer template class.
template <typename T>
class customer // acts as base observer class
{
char name[50];
public:
customer()
{
cout << __FUNCTION__ "(): " << "DEFAULT CONS\n";
}
customer(char* nm)
{
strcpy_s(name, nm);
cout << __FUNCTION__ "(): " << "name set to " << name << "\n";
}
char * getName()
{
return(name);
}
virtual void update(int c)
{
}
};
class customerC: public customer<customerC>
{
int c;
public:
customerC()
{
cout << __FUNCTION__ "(): " << "DEFAULT customerc cons\n";
}
customerC(char* nm):customer<customerC>(nm)
{
cout << __FUNCTION__ "(): " << "customer is " << getName() << "\n";
}
void update(int val)
{
cout << __FUNCTION__ "(): c to " << c << "\n";
c = val;
}
};
class customerD: public customer<customerD>
{
int d;
public:
customerD()
{
cout << __FUNCTION__ "(): " << "DEFAULT customerd cons\n";
}
customerD(char* nm):customer<customerD>(nm)
{
cout << __FUNCTION__ "(): " << "customer is " << getName() << "\n";
}
void update(int val)
{
cout << __FUNCTION__ "(): c to " << d << "\n";
d = val;
}
};
template<typename T>
class agent
{
char name[50];
int x;
protected:
vector<customer<T>*> custList;
public:
agent()
{
cout << __FUNCTION__ "(): " << "DEFAULT agent cons\n";
}
virtual void setx(int c)
{
cout << __FUNCTION__ "(): " << "Setting x to " << c << "\n";
//// x = c;
//// notifyObs();
}
virtual void getx()
{
cout << __FUNCTION__ "(): " << "x = " << x << "\n";
}
void addCust(customer<T>* cobj)
{
cout << __FUNCTION__ "(): " << "Adding customer " << cobj->getName() << " to list.\n";
custList.push_back(cobj);
}
void showCust()
{
cout << __FUNCTION__ "(): " << "Customers are:\n";
if(custList.empty())
cout << "\n\nYou have no items.";
else
{
vector<customer<T>*>::iterator cs;
for(cs = custList.begin(); cs != custList.end(); ++cs)
{
cout << (*cs)->getName() << "\n";
}
}
}
int notifyObs()
{
cout << __FUNCTION__ "(): " << "Customers notified are:\n";
if(custList.empty())
cout << "\n\nYou have no items.";
else
{
vector<customer<T>*>::iterator cs;
for(cs = custList.begin(); cs != custList.end(); ++cs)
{
cout << (*cs)->getName() << "\n";
(*cs)->update(x);
}
}
return 0;
}
};
class agentS: public agent<agentS>
{
int x;
public:
agentS()
{
cout << __FUNCTION__ "(): " << "DEFAULT agentS cons\n";
}
void setx(int c)
{
cout << __FUNCTION__ "(): " << "Setting x to " << c << "\n";
x = c;
notifyObs();
}
void getx()
{
cout << __FUNCTION__ "(): " << "x = " << x << "\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
customerC cobj("c1");
customerD dobj("c2");
agentS agS;
agS.addCust(cobj);
//// agS.addCust<customer<customerC>>(cobj);
//// agS.addCust(dobj);
agS.showCust();
agS.setx(4);
return(0);
}
I get compilation error
error C2664: 'agent<T>::addCust' : cannot convert parameter 1 from 'customerC' to 'customer<T> *'
I know the way I have called addCust is wrong but still not getting any idea as to call it.
Any hint to resolve this issue?
Also is the way I have created agents class correct?
class agentS: public agent<agentS>
When I call addCust() function I pass observer objects.
By creating your agentS class that way, the effective signature for addCust becomes void addCust(customer<agentS>* cobj);. However, your customer classes are not templated on the agent type (there doesn't actually seem to be a reason for it to be templated).
You appear to be mixing dynamic polymorphism (inheritance and virtual functions with customer) and static polymorphism (templates to create a vector of one type of customer). Either of these options on their own would make more sense:
Dynamic polymorphism (inheritance). You can store different types of customer in the same container, by storing the base class pointer, and use the customer base class and virtual functions to tread them in the same way:
struct customer {};
struct customerC : customer {};
struct customerD : customer {};
struct agent
{
void addCust(customer* customer) { ... }
std::vector<customer*> custList;
};
int main()
{
agent a;
customerC c;
a.addCust(&c);
}
Static polymorphism (templates). The agent class is templated on the customer type, so the vector can only contain one type of customer, but it's easy to create a specific agent for any given customer type:
struct customer {};
struct customerC : customer {};
struct customerD : customer {};
template<CustomerT>
struct agent
{
void addCust(CustomerT* customer) { ... }
std::vector<CustomerT*> custList;
};
int main()
{
agent<customerC> a;
customerC c;
a.addCust(&c);
}

Inheritance and pointers in C++

I have this code example and I want to understand why it behaves the way it does. This is a question from a past exam paper in an intro C++ course. I'm studying for the exam now and trying to solidify my understanding of class inheritance.
#include <iostream>
using namespace std;
class Bird {
public:
virtual void noise() { cout << "mumble" << endl; }
void move() { noise(); cout << "fly" << endl; }
};
class Canary: public Bird {
public:
void noise() { cout << "chirp" << endl; }
void move() { noise(); cout << "flap" << endl; }
};
class Tweety: public Canary {
public:
void noise() { cout << "tweet" << endl; }
void move() { noise(); cout << "run" << endl; }
};
int main() {
Canary *yellow = new Tweety();
yellow->noise();
yellow->move();
return 0;
}
I've run this code, and the output is:
tweet
tweet
flap
Which means it's calling the Tweety implementation of noise(), but it's calling the Canary implementation of move(). I'm confused about that. I understand the idea of polymorphism, and noise() is virtual, so it makes sense that it calls the Tweety version, since *yellow is a pointer to a Tweety. But why does it call the Canary version of move()?
I think what's confusing me, is the line:
Canary *yellow = new Tweety();
This says that *yellow is a Canary pointer, which points to a Tweety object. I'm sort of ok with that, because I get that pointers to base class can point to derived class. But *yellow points to a Tweety, so why doesn't it use Tweety's move()?
Thanks in advance for any help.
noise is virtual, so it is dynamically dispatched to the Tweety implementation when you call it.
move in not virtual, so the version to call is decided at compile time based on the type of you are dispatching the call through. Since yellow is a Canary the compiler does resolve what will be called at compile time and will explicitly call the move method in Canary.
The move() should also be virtual otherwise the version of the pointer type is called.
Sean and Alex are spot on.
Here are some more call cases that should help make sense of the different scenarios.
#include <iostream>
using namespace std;
class Bird {
public:
virtual void noise() { cout << "mumble" << endl; }
void move() { noise(); cout << "fly" << endl; }
void noise2() { cout << "mumble2" << endl; }
virtual void move2() { noise2(); cout << "fly2" << endl; }
};
class Canary: public Bird {
public:
void noise() { cout << "chirp" << endl; }
void move() { noise(); cout << "flap" << endl; }
void noise2() { cout << "chirp2" << endl; }
void move2() { noise2(); cout << "flap2" << endl; }
};
class Tweety: public Canary {
public:
void noise() { cout << "tweet" << endl; }
void move() { noise(); cout << "run" << endl; }
void noise2() { cout << "tweet2" << endl; }
void move2() { noise2(); cout << "run2" << endl; }
};
int main() {
Canary *yellow = new Tweety();
yellow->noise();
yellow->move();
yellow->noise2();
yellow->move2();
return 0;
}
/* OUTPUT:
tweet <- virtual dispatch
tweet <- virtual dispatch, via Bird::move()
flap <- direct call
chirp2 <- direct call
tweet2 <- direct call, from Tweety::move2()
run2 <- virtual dispatch
*/

Why won't my point in Species class point to its heterogeneous class

My code consists of a class animal and 2 sub classes inheriting animal charactistics - amphibian, and fish. The code compiles but the oorder of the deconstructors kills them from bottom to top but i want them to be killed from top to bottom as the display function order suggests-
Here is my code:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Animal{
public:
Animal(string name, string diet, bool queue)
: name_species(name), regime(diet), queue(queue){
if(name == ""){cout << "Error, name can't be empty!" << endl; }
else { cout << "A new animal" << endl; }}
virtual ~Animal(){ cout << "End of animal" << endl; }
virtual void display()const;
protected:
string name_species;
string regime;
bool queue;
};
void Animal::display() const{
cout << "I present the species " << name_species << endl;
}
class Fish : public Animal {
public:
Fish(string name, unsigned int scales, string diet = "Carnivore", bool queue = true)
: Animal(name, diet, queue), scales(scales){ cout << "Add a fish" << endl; }
~Fish(){ cout << "Fish species " << name_species << " is turned off. " << endl; }
void display() const override;
private:
unsigned int scales;
};
void Fish::display() const {
Animal::display();
if(queue == true){cout << "I have a tail "; }
else { cout << "I don't have a tail "; } cout << "and i follow " << regime << endl;
cout << "I have " << scales << " scales" << endl;
}
class Amphibian : public Animal {
public: Amphibian(string name, string diet, unsigned int claws = 4, bool queue = false)
: Animal(name, diet, queue), claws(claws){ cout << "Add an amphibian" << endl; }
void affiche() const;
~Amphibian(){ cout << "Amphibian species " << name_species << " is turned off. " << endl; }
private:
unsigned int claws;
};
void Amphibian::display() const {
Animal::display();
if(queue == true){ cout << "I have a tail "; }
else { cout << "I don't have a tail " ; } cout << "and i follow " << regime << endl;
cout << "I have " << scales << " scales " << endl;
}
class Species {
public:
virtual void display()const = 0;
virtual ~Species();
private:
vector<Animal*> animals;
};
void Species::display()const{
for(size_t i(0); i < animals.size(); ++i){
animals[i]->display(); }
}
Species::~Species(){
for(size_t i(0); i < animals.size(); ++i){
delete animals[i];
}
}
int main()
{
Amphibian kermit("lizard", "insects");
Fish nemo("dolphin", 6);
Fish sala("salamander", 4);
Animal* animal(&kermit);
animal->display();
animal = &nemo;
animal->display();
return 0;
}
Nothing inherits from class Species so conversion not possible using assignment technique.
There are no methods in Species to convert an Animal into a Species, so no luck there. Compiler running out of ideas on how to convert Animal to Species.
Looks like Species is a container of Animals. You will need to supply a method that adds an Animal to the container inside Species or make the container public.
You want something like this:
Species s;
s.animals.push_back(&kermit);
The following code suggests that you see Species as something more general than Animal:
Species* animal(&kermit);
animal->display();
animal = &nemo;
In this case you shall make sure the inheritance is declared, by changing the class definition to :
class Animal : Species {
...
};
Some remarks nevertheless:
as all species have a name, whether vegetal or animal, you could consider to move member Animal::name_species to class Species;
the fact that the name of the class Species is in plural, that you have a vector as member, and that every element of this member is displayed or deleted when the corresponding operation is called for the member tends however to suggest that Species is an aggregation of Animals. It is then not clear how you add elements to your vector.
Rather than using raw pointers in the aggregation, you could use shared_ptr instead. You then don't need to delete the aniamls yourself.

How does g++ compiler know which vtable ptr to use if their are multiple vtable ptr in a base class?

I want to know know how does g++ compiler knows which table to use if their are multiple vtable present in a base class. Like the following example.
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
using namespace std;
class sample1
{
private:
int b;
public:
sample1():b(34)
{
cout << "In sample1 constructor" << endl;
}
virtual void print_b()
{
cout << this->b << endl;
}
void print_all()
{
this->print_b();
}
void sample_print_()
{
//cout << this->a << "String : " << this->str1 << endl;
cout << "hello" << endl;
this->print_all();
}
};
class sample2
{
private:
int b1;
public:
sample2():b1(34)
{
cout << "In sample1 constructor" << endl;
}
virtual void print_b1()
{
cout << this->b1 << endl;
}
void print_all1()
{
this->print_b1();
}
};
class sample : public sample1 , public sample2
{
private:
int a;
char *str1;
public:
sample():a(12),sample1()
{
strcpy(this->str1,"hello world");
cout << "In Constructor" << endl;
}
~sample()
{
free(this->str1);
cout << "In Destructor" << endl;
}
void sample_print()
{
//cout << this->a << "String : " << this->str1 << endl;
cout << "hello" << endl;
this->print_all();
}
virtual void print_a()
{
cout << this->a <<endl;
}
};
In above example, child class sample has two parent classes sample1 and sample2 and each of these class have vtable of their own. What if i call a virtual function from sample(child class)? How does the compiler know, in which class that virtual function is present so that it call use that particular vtable pointer ? I know their will be two vtable pointer present in sample(child class) class , so how does compiler know which one to use ?