I'm new to object programming and to c++.
I'm applying what is taught in SoloLearn c++ course about class inheritance.
Class enemy: enemy.h
class enemy
{
public:
enemy();
~enemy();
void setAttackPower();
protected:
int aP;
};
enemy.cpp:
#include "enemy.h"
#include <iostream>
using namespace std;
enemy::enemy()
{
cout << "constructor" << endl;
}
enemy::~enemy()
{
cout << "destructor" << endl;
}
int aP=0;
void setAttackPower(int a) {
aP = a;
}
class ninja, that inherits from enemy:
ninja.h:
#include "enemy.h"
class ninja: public enemy
{
public:
ninja();
~ninja();
void attack();
};
ninja.cpp:
#include "ninja.h"
#include <iostream>
using namespace std;
ninja::ninja()
{
}
ninja::~ninja()
{
}
void attack() {
cout << "Ninja attack " << aP << endl;
}
and the error is:
identifier "aP" is undefined. I can't see the problem. Can anyone help me?
enemy.cpp
int aP=0;
You created 2 values with same name: 1st belongs to class and the 2nd is a global value. The compiler cannot deside which one you are trying to use.
Related
I have an abstract class Player and its children AI and Human. In my main, when I create two objects Human and AI it works fine. But once I use them as parameters in a function that is waiting for Player pointer type, then their type is no longer AI and Human but both are Player objects.
Game.hpp :
#include "Player.hpp"
#include "Human.hpp"
class Game {
private:
Player *j1, *j2;
public:
Game();
Game(Player*, Player*);
void setP1(Player*);
void setP2(Player*);
Player* getP1();
Player* getP2();
};
Game.cpp :
#include "Game.hpp"
Game::Game(){
}
Game::Game(Player *pp1, Player *pp2){
p1 = pp1;
p2 = pp2;
}
void Game::setP1(Player *pp1){
p1 = pp1;
}
void Game::setP2(Player *pp2){
p2 = pp2;
}
Player* Game::getP1(){
return p1;
}
Player* Game::getP2(){
return p2;
}
Player.hpp :
#ifndef PLAYER_H
#define PLAYER_H
#include <string>
using std::string;
class Player {
protected:
string nom;
int age;
public:
Player();
Player(string, int);
void setNom(string);
void setAge(int);
string getNom();
int getAge();
virtual void upAge() = 0;
};
#endif
Here is the main.cpp :
#include "Player.hpp"
#include "Human.hpp"
#include "Game.hpp"
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
int main(){
Player *j;
Human h;
Game Game;
cout << typeid(h).name() << endl;
Game.setJ1(&h);
cout << typeid(Game.getJ1()).name() << endl;
return 0;
}
I would like the two cout to display the same result. But the first displays Human, and the second displays Player. How can I handle this ?
EDIT 1 : added Player.hpp file.
Base class Player must contain a virtual function to get the type name as derived class.
check typeid below example from cpp reference.
#include <iostream>
#include <string>
#include <typeinfo>
struct Base {}; // non-polymorphic
struct Derived : Base {};
struct Base2 { virtual void foo() {} }; // polymorphic
struct Derived2 : Base2 {};
int main() {
// Non-polymorphic lvalue is a static type
Derived d1;
Base& b1 = d1;
std::cout << "reference to non-polymorphic base: " << typeid(b1).name() << '\n';
Derived2 d2;
Base2& b2 = d2;
std::cout << "reference to polymorphic base: " << typeid(b2).name() << '\n';
}
Possible output:
reference to non-polymorphic base: 4Base
reference to polymorphic base: 8Derived2
The following code gives me an error.
Error: overriding 'virtual void Animal::getClass()', where it says virtual void getClass() { cout << "I'm an animal" << endl; }
Error: conflicting return type specified for 'virtual int Dog::getClass()', where it says getClass(){ cout << "I'm a dog" << endl; }
Also, it says:
Class 'Dog' has virtual method 'getClass' but non-virtual destructor
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include<sstream>
#include <stdlib.h> // srand, rand
#include <stdio.h>
using namespace std;
class Animal{
public:
void getFamily(){ cout << "We are animals " << endl;}
virtual void getClass() { cout << "I'm an animal" << endl; }
};
class Dog : public Animal{
public:
getClass(){ cout << "I'm a dog" << endl; }
};
void whatClassAreYou(Animal *animal){
animal -> getClass();
}
int main(){
Animal *animal = new Animal;
Dog *dog = new Dog;
animal->getClass();
dog->getClass();
whatClassAreYou(animal);
whatClassAreYou(dog);
return 0;
}
Change the definition inside class Dog to:
void getClass() { /* ... */ }
When you declare it with no return type, the compiler sets the return type to int. This yields an error because the overriden method has to have the same return type as the base class method it overrides.
You are trying to declare function with no return type which was allowed in older version of C++. But the ISO C++ standard doesn't allow this (although some compilers may still allow, I guess like Codegear C++Builder 2007 that shows no error or warning at all). It has been mentioned in the standard - §7/7 footnote 78, and §7.1.5/2 footnote 80: implicit int banned.
Here is a reason why it was discarded:
void HypotheticalFunction(const Type);
In this function, what would be the argument type - const argument of type Type or argument of type const int with a name Type ?
Here is a better version of how you could define your class:
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include<sstream>
#include <stdlib.h> // srand, rand
#include <stdio.h>
using namespace std;
class Animal{
public:
void getFamily(){ cout << "We are animals " << endl;}
virtual void getClass() { cout << "I'm an animal" << endl; }
};
class Dog : public Animal{
public:
virtual void getClass(){ cout << "I'm a dog" << endl; }
};
void whatClassAreYou(Animal *animal){
animal -> getClass();
}
int main(){
Animal *animal = new Animal;
Dog *dog = new Dog;
animal->getClass(); // I'm an animal
dog->getClass(); // I'm a dog
Animal *animal1 = new Dog;
animal1->getClass(); // I'm a dog
whatClassAreYou(animal1); // I'm a dog
whatClassAreYou(animal); // I'm an animal
return 0;
}
§ C.1.6 Change: Banning implicit int In C++
a decl-specifier-seq must contain a type-specifier, unless it is followed by a declarator for a
constructor, a destructor, or a conversion function.
You are missing your type-specifier which is illegal in modern C++.
Use:
void getClass(){ cout << "I'm a dog" << endl; }
I have a little problem with polymorphism. My simple code:
Animal.h
class Animal {
public:
Animal();
Animal(const Animal& orig);
virtual ~Animal();
virtual void get();
};
Animal.cpp
#include "Animal.h"
#include <iostream>
using namespace std;
Animal::Animal() {
cout << "Animal is born" << endl;
}
void Animal::get() {
cout << "get() from an Animal!" << endl;
}
Bird.h
class Bird : public Animal {
public:
Bird();
Bird(const Bird& orig);
virtual ~Bird();
void get();
};
Bird.cpp
#include "Bird.h"
#include <iostream>
using namespace std;
Bird::Bird() {
cout << "Bird is born" << endl;
}
void Bird::get() {
cout << "get() from a Bird!" << endl;
}
Chicken.h
#include "Bird.h"
class Chicken : public Bird {
public:
Chicken();
Chicken(const Chicken& orig);
virtual ~Chicken();
void get();
};
Chicken.cpp
#include "Chicken.h"
#include <iostream>
using namespace std;
Chicken::Chicken() {
cout << "Chicken is born" << endl;
}
void Chicken::get() {
cout << "get() from a Chicken!" << endl;
}
There is also a factory method returning an Animal* pointer to the concrete implementation based on input:
Factory.h
#include "Animal.h"
#include "Bird.h"
class Factory {
public:
Factory();
Factory(const Factory& orig);
virtual ~Factory();
Animal* generateAnimal();
Bird* generateBird();
};
Factory.cpp
#include "Factory.h"
#include "Animal.h"
#include "Bird.h"
#include "Chicken.h"
#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;
Animal* Factory::generateAnimal() {
string choice;
cout << "What do you want? 1-Animal, 2-Bird, 3-Chicken" << endl;
cin >> choice;
Animal* animal;
if (choice.at(0) == '1') {
cout << "You chose Animal" << endl;
animal = new Animal();
return animal;
} else if (choice.at(0) == '2') {
cout << "You chose Bird" << endl;
animal = new Bird();
return animal;
} else if (choice.at(0) == '3') {
cout << "You chose Chicken" << endl;
animal = new Chicken();
return animal;
} else {
cout << "Wrong input" << endl;
exit(1);
}
}
Bird* Factory::generateBird() {
string choice;
cout << "What do you want? 1-Animal, 2-Bird, 3-Chicken" << endl;
cin >> choice;
Bird* bird;
if (choice.at(0) == '2') {
cout << "You chose Bird" << endl;
bird = new Bird();
return bird;
} else if (choice.at(0) == '3') {
cout << "You chose Chicken" << endl;
bird = new Chicken();
return bird;
} else {
cout << "Wrong input" << endl;
exit(1);
}
}
I omitted ctors & dtors.
main.cpp
#include <cstdlib>
#include <iostream>
#include "Factory.h"
#include "Animal.h"
#include "Bird.h"
#include "Chicken.h"
using namespace std;
int main(int argc, char** argv) {
Factory factory;
Animal* animal = factory.generateAnimal();
animal->get();
return 0;
}
The concrete implementation of an Animal class is resolved during runtime.
It's obvious, that removing the virtual keyword from Animal class results in calling Animal implementation of get() method, whether animal* points to Bird or Chicken.
What do you want? 1-Animal, 2-Bird, 3-Chicken
3
You chose Chicken
Animal is born
Bird is born
Chicken is born
get() from an Animal!
It's also obvious, that calling the virtual get() method results in polymorphic call to the concrete subclass.
What concerns me is this situation:
Instead of
Animal* animal = factory.generateAnimal();
animal->get();
we have
Bird* bird = factory.generateBird();
bird->get();
We have a pointer to Bird class, in which the get() method is NOT declared virtual. The output is:
What do you want? 1-Animal, 2-Bird, 3-Chicken
3
You chose Chicken
Animal is born
Bird is born
Chicken is born
get() from a Chicken!
How does it happen, that call to non-virtual function results in virtual call to the subclass?
Is "virtualism" inherited? If it is, is it somehow possible to perform a non-virtual call to the pointer class, instead of implementation class?
A virtual method remains virtual in inherited classes even if you don't specify the virtual keyword. Actually in C++11 you have a way to specify that method is overridden:
class Bird {
void get() override;
}
You can even specify the virtual keyword on overridden methods just to remember it yourself but you can't "remove" the dynamic dispatch of the method.
The only thing you are allowed to do is to choose the implementation by specifying it:
Bird *bird = new Bird();
bird->Animal::get();
We have a pointer to Bird class, in which the get() method is NOT virtual.
That's wrong. It is virtual. Virtual functions cannot be made non-virtual by derived classes. The virtual keyword is just optional there, but it has no effect.
In short, yes, virtual is "inherited". In other words, you can't "change it back" from virtual to non-virtual when you inherit from a base-class. That would make the system very fragile to typos (forget virtual, and all of a sudden you call a different member depending on which route you came to the object).
Say you have a class hierarchy
class A{
void f();
};
class B : public A{
void f();
};
class C : public B{
void f();
};
\\...
class O : public N{
void f();
};
class P : public O{
virtual void f();
};
class Q : public P{
virtual void f();
};
class R : public Q{
void f();
};
\\...
class Z : public Y{
void f();
};
As soon as, traversing the hierarchy, a member is declared to be virtual, it will be so for further derived classes too. In case you are wondering, there is no way for making Z::f() non-virtual if Q::f() is virtual.
What this mean is explained in this code:
Z z;
A& a = z;
O& o = z;
P& p = z;
Q& q = z;
Z& z = z;
a.f(); //calls A::f()
o.f(); //calls O::f()
p.f(); //calls Z::f()
q.f(); //calls Z::f()
z.f(); //calls Z::f()
z.A::f(); //calls A::f()
z.R::f(); //calls R::f()
of course this assumes that O::f() is overridden.
See also my answer to a related question.
Please have a look at the following code
GameObject.h
#pragma once
class GameObject
{
protected:
int id;
public:
int instances;
GameObject(void);
~GameObject(void);
virtual void display();
};
GameObject.cpp
#include "GameObject.h"
#include <iostream>
using namespace std;
static int value=0;
GameObject::GameObject(void)
{
value++;
id = value;
}
GameObject::~GameObject(void)
{
}
void GameObject::display()
{
cout << "Game Object: " << id << endl;
}
Round.h
#pragma once
#include "GameObject.h"
class Round :
public GameObject
{
public:
Round(void);
~Round(void);
};
Round.cpp
#include "Round.h"
#include "GameObject.h"
#include <iostream>
using namespace std;
Round::Round(void)
{
}
Round::~Round(void)
{
}
void display()
{
cout << "Round Id: " << id;
}
I am getting 'id' : undeclared identifier error in Round class. Why is this? Please help!
In this function:
void display()
{
cout << "Round Id: " << id;
}
You are trying to access a variable named id inside a non-member function. The compiler cannot resolve that name, because id is not the name of any global nor local variable, therefore you get an error complaining that the identifier was not declared.
If you meant to make display() a member function of Round(), you should have declared it as such:
class Round : public GameObject
{
public:
Round(void);
~Round(void);
void display(); // <==
};
And defined it this way:
void Round::display()
// ^^^^^^^
{
...
}
This way, function Round::display() would override the virtual function GameObject::display().
You declared a globally scoped method named display in your Round.cpp file. Edit your header and cpp like this:
Round.h
#pragma once
#include "GameObject.h"
class Round :
public GameObject
{
public:
Round(void);
virtual ~Round(void);
virtual void display(void);
};
Round.cpp
#include "Round.h"
#include "GameObject.h"
#include <iostream>
using namespace std;
Round::Round(void)
{
}
Round::~Round(void)
{
}
void Round::display()
{
cout << "Round Id: " << id;
}
Note - you should make the destructor in GameObject virtual
#include <iostream>
using namespace std;
class Person {
public:
void sing();
};
class Child : public Person {
public:
void sing();
};
Person::sing() {
cout << "Raindrops keep falling on my head..." << endl;
}
Child::sing() {
cout << "London bridge is falling down..." << endl;
}
int main() {
Child suzie;
suzie.sing(); // I want to know how I can call the Person's method of sing here!
return 0;
}
suzie.Person::sing();
The child can use Person::sign().
See http://bobobobo.wordpress.com/2009/05/20/equivalent-of-keyword-base-in-c/ for a good explanation.