Recently, I started working with classes and, today, class inheritance. I created a simple program to expand my perception of inheritance. The program calculates the average grade of a class. I understand the vast majority of the code I have written, but there are some exceptions (listed below the code). Any and all help would be appreciated.
Code
#include "stdafx.h"
#include <iostream>
using namespace std;
class CAverage {
private:
double VSubCount, VAverage, VMark, VSum, VNum;
public: CAverage(int); // Constructor.
void MTake_action() {
MAsk_input(); // Calls the method “MAsk_input()“ within this class.
MCalculate_average(); // Calls the method “MCalculate_average()“ within
// this class.
MPrint_result(); // Calls the method “MPrint_result()“ within this class.
}
void MCalculate_average() {
VAverage = VSum / VNum;
}
void MAsk_input() {
VSum = 0;
VNum = 0;
int VNumber;
for (int i = 0; i < VSubCount; i++) {
cout << "Enter your " << i + 1 << " mark: ";
cin >> VNumber;
if (VNumber > 0) {
VMark = VNumber;
VSum += VMark;
VNum++;
}
}
}
void MPrint_result()
{
system("cls");
if (((VSum / 3) <= 0) || ((VSum / 3) > 10)) {
cout << "Incorrect input." << endl;
} else {
cout << "Average: " << VAverage << endl;
}
}
};
// Creates a child class and makes that this class could view/get public methods,
// variables, etc of “CAverage“.
class CGroup : public CAverage {
private:
int VClassMembers;
void MAsk_input() {
for (int i = 0; i < VClassMembers; i++) {
system("cls");
cout << "[" << i + 1 << " student]" << endl;
CAverage::MAsk_input(); // Calls the method “MAsk_input()“ within
// the parent class (“CAverage“).
}
}
public: CGroup(int, int);
void MTake_action() {
MAsk_input(); // Calls the method “MAsk_input()“ within this class.
CAverage::MCalculate_average(); // Calls the method “MCalculate_average()“
// within the parent class (“CAverage“).
CAverage::MPrint_result(); // Calls the method “MPrint_result()“ within the
// parent class (“CAverage“).
}
};
CAverage::CAverage(int VSubjectCount) {
VSubCount = VSubjectCount;
}
CGroup::CGroup(int VOther, int VInteger) : CAverage(VOther) {
VClassMembers = VInteger;
}
int main() {
CGroup avg(2, 5); // Creates an object, named “avg“.
avg.MTake_action(); // Calls the child classes' method “MTake_action()“.
return 0;
}
So, how would one explain these parts?
CAverage::CAverage(int VSubjectCount) {
VSubCount = VSubjectCount;
}
CGroup::CGroup(int VOther, int VInteger) : CAverage(VOther) {
VClassMembers = VInteger;
}
I think that this
CAverage(int);
and this
CGroup(int, int);
call the constructors? Or, are they themselves the constructors?
And, are all of the comments, made by me, correct?
I think that this
CAverage(int);
and this
CGroup(int, int);
call the constructors? Or, are they themselves the constructors?
Your second presumption is correct, both are constructors.
CAverage::CAverage(int VSubjectCount) {
VSubCount = VSubjectCount;
}
This snippet initializes the variable VSubCount within the superclass.
CGroup::CGroup(int VOther, int VInteger) : CAverage(VOther) {
VClassMembers = VInteger;
}
This is a little more complex, and shows key concepts of inheritance.
: CAverage(VOther)
Is calling the parent constructor, to initialize the private member VSubCount, in CAverage, since CGroup cannot access it.
VClassMembers = VInteger;
initializes the member VClassMembers in the subclass. Otherwise, your comments are correct.
Related
I am trying to figure out how to use GetAsyncKeyState with private attributes forward and backwards from a base class. I need to be able to reset GetAsyncKeyState to other keypresses. Any idea?
Maybe overriding forward and backwards with other keypresses?
#include <iostream>
#include <windows.h>
#include <string>
#include<conio.h>
using namespace std;
bool reset_defaults = false;
class Base {
protected: // OR private
int forward = VK_UP, backwards = VK_DOWN;
public: //...
}
////////////
class Move : public Base {
public:
Base def;
int move() {
while (true) {
if (GetAsyncKeyState(forward) < 0){
cout << ("forward >>>\n");
if (GetAsyncKeyState(forward) == 0){
cout << ("Stopped\n");
}
}
if (GetAsyncKeyState(VK_SPACE) < 0){break;}
}
}
int main() {
Move move;
move.move();
}
Sorry, but I don't think I understand the whole logic of this yet.
PS UPDATE:
How can I override baseKeys values:
class MovementKeys {
protected:
int baseKeys(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right){
default_key_forward = VK_UP;
default_key_backward = VK_DOWN;
default_key_left = VK_LEFT;
default_key_right = VK_RIGHT;
}
public:
int definedCommand(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right) {
while (reset_defaults == false)
{
cout << ("HERE 1 \n");
if (GetAsyncKeyState(default_key_forward) < 0)
{
cout << ("forward\n");
}
if (GetAsyncKeyState(default_key_backward) < 0)
{
court << ("backwards\n");
}
if (GetAsyncKeyState(default_key_left) < 0)
{
cout << ("left\n");
}
if (GetAsyncKeyState(default_key_right) < 0)
{
cout << ("right\n");
}
if (GetAsyncKeyState(VK_SPACE) < 0) { break; }
}
return 0;
}
int derived_newKeys(int default_key_forward, int default_key_backward, int default_key_left, int default_key_right) {
return baseKeys(default_key_forward, default_key_backward, default_key_left, default_key_right);
}
You probably want to use member variables to store the keys. Instead of deriving the class with new keys, you set the variables in constructors (to default or to changed values) and can also change the key assignment later on.
You probably want to create a separate class, which reacts on the events.
#include <iostream>
#include <windows.h>
#include <conio.h>
using namespace std;
class World {
public:
void forward() { y--; };
void backward() { y++; };
void left() { x--; };
void right() { x++; };
private:
int x = 0;
int y = 0;
};
class MovementKeys {
// member variables
private:
// keep reference to world instead of copy; main() has to make sure World object outlives MovementKeys object
World& world;
int key_forward;
int key_backward;
int key_left;
int key_right;
public:
// constructor, which only sets world, but keeps the keys at their default settings
//
// world has to be initialized before the constructor function body
// as references have no default value
// put initialization in member initialization list
MovementKeys(World& w) : world(w)
{
key_forward = VK_UP;
key_backward = VK_DOWN;
key_left = VK_LEFT;
key_right = VK_RIGHT;
}
// constructor which modifies keys
MovementKeys(World& w, int change_key_forward, int change_key_backward, int change_key_left, int change_key_right) : world(w)
{
changeKeys(change_key_forward, change_key_backward, change_key_left, change_key_right);
}
// command loop controlled by keys
int definedCommand()
{
while (true)
{
cout << ("HERE 1 \n");
if (GetAsyncKeyState(key_forward) < 0)
{
cout << ("forward\n");
world.forward();
}
if (GetAsyncKeyState(key_backward) < 0)
{
cout << ("backwards\n");
world.backward();
}
if (GetAsyncKeyState(key_left) < 0)
{
cout << ("left\n");
world.left();
}
if (GetAsyncKeyState(key_right) < 0)
{
cout << ("right\n");
world.right();
}
// optionally change keys from within while loop
if (GetAsyncKeyState(VK_BACK) < 0)
{
key_forward = VK_RETURN;
}
if (GetAsyncKeyState(VK_SPACE) < 0)
{
break;
}
}
return 0;
}
// function for changing the keys stored in the member variables
// can be called by constructor or externally
void changeKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right)
{
key_forward = change_key_forward;
key_backward = change_key_backward;
key_left = change_key_left;
key_right = change_key_right;
}
};
int main()
{
World earth;
// use default keys, declares local variable and constructs MovementKeys object called move
MovementKeys move(earth);
move.definedCommand();
// use custom keys, share same world, declares local variable and constructs MovementKeys object called move2
// static_cast<int>() with a letter in a literal char parameter works, because the VK_ values of letter keys are the actual ASCII values (on purpose by Microsoft, I would assume)
MovementKeys move2(earth, static_cast<int>('W'), static_cast<int>('S'), static_cast<int>('A'), static_cast<int>('D'));
move2.definedCommand();
// change keys in move2
move2.changeKeys(VK_LBUTTON, VK_RBUTTON, VK_CONTROL, VK_SHIFT);
move2.definedCommand();
// run first one again for the fun of it
move.definedCommand();
}
Alternatively passing World& only, where it is used in definedCommand (and at the same time be able to use several worlds):
class World {
// ...
};
class MovementKeys {
// member variables without world, we can also put default value here
private:
int key_forward = VK_UP;
int key_backward = VK_DOWN;
int key_left = VK_LEFT;
int key_right = VK_RIGHT;
public:
// default constructor with no parameters, delegate to other constructor
// delegating not necessary, as the default values are set above anyway; just demonstrating various techniques for initializing member variables
MovementKeys() : MovementKeys(VK_UP, VK_DOWN, VK_LEFT, VK_RIGHT) {};
// constructor which modifies keys, put everything in member initialization list
MovementKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right) : key_forward(change_key_forward), key_backward(change_key_backward), key_left(change_key_left), key_right(change_key_right) {};
// command loop controlled by keys, pass World& here as parameter
int definedCommand(World& world)
{
while (true)
{
// ...
}
return 0;
}
void changeKeys(int change_key_forward, int change_key_backward, int change_key_left, int change_key_right)
{
// ...
}
};
int main()
{
// use default keys, declares local variable and constructs MovementKeys object called move
MovementKeys move;
// use custom keys, declares local variable and constructs MovementKeys object called move2
MovementKeys move2(static_cast<int>('W'), static_cast<int>('S'), static_cast<int>('A'), static_cast<int>('D'));
MovementKeys defaultMenuKeys;
World earth;
World moon;
World menu; // between moving in worlds, we want to control some settings in a menu
move.definedCommand(earth);
move2.definedCommand(earth);
move2.definedCommand(moon);
// change keys in move2
move2.changeKeys(VK_LBUTTON, VK_RBUTTON, VK_CONTROL, VK_SHIFT);
move2.definedCommand(earth);
defaultMenuKeys.definedCommand(menu);
// run first one again for the fun of it
move.definedCommand(moon);
}
You can introduce a (class) enum with a list of the states, why definedCommand() returns:
// outside or can be put into MovementKeys and henceforth used as MovementKeys::ReturnReason
class enum ReturnReason { EXIT, NEWKEYS, SHOWMENU, SWITCHWORLD };
// in class MovementKeys
ReturnReason definedCommand() {
// ...
return NEWKEYS;
// ...
return EXIT;
// ...
return SHOWMENU;
// ...
}
// in main()
ReturnReason r = definedCommand();
if (r == NEWKEYS)
move2.changeKeys(...);
else if (r == EXIT)
return 0;
If you use that 'trick' to also control the menu, it could make sense to use virtual inheritance now for World. As the normal World and the menu World probably react quite differently. (The base class (ancestor) would be World, which is recognized by MovementKeys. Your actual Worlds are objects of derived (children) classes, with more specific behaviour.
definedCommand then can be called and run with any derived class of the base class World.
So in my program, I'm using polymorphism, which could also explain some of the issues that I'm having.
This is my pure abstract class:
class Event {
public:
Event();
~Event();
virtual int returnType();
};
Then I have a room class that sets events to a particular room:
class Room {
private:
Event * e;
bool player = false;
bool bEvent = false;
public:
Room();
~Room();
Event * getEvent();
void setEvent(Event *);
bool getPlayer();
void setPlayer(bool);
bool getBoolEvent();
void setBoolEvent(bool);
};
And here are my function definitions:
Event * Room::getEvent() {
return e;
}
void Room::setEvent(Event * n) {
e = n;
}
bool Room::getPlayer() {
return player;
}
void Room::setPlayer(bool p) {
player = p;
}
bool Room::getBoolEvent() {
return bEvent;
}
void Room::setBoolEvent(bool b) {
bEvent = b;
}
Here is my bats class which is a derived class from event: The functions are the same, so here are the function definitions:
int Bats::returnType() {
return 1;
}
So in my program, I am using a 2d vector of Rooms, and then assigning events to these rooms via polymorphism. The problem is that I don't think the changes are persisting, at least with the polymorphism, even when passing by reference.
Here is the function where I am setting the bat event to a certain room in the 2d vector:
vector<vector<Room>> Game::setEvents(vector<vector<Room>> &grid) {
Bats b1;
Event * eb1 = &b1;
//Set player
int r1 = rand()%gridSize;
int r2 = rand()%gridSize;
grid[r1][r2].setPlayer(true);
//Set bats
grid[0][0].setBoolEvent(true);
grid[0][0].setEvent(eb1);
cout << "Function example: " << grid[0][0].getEvent()->returnType() << endl;
return grid;
}
As an output I get Function example: 1;
However, when we move into the main (in this case Game::play()) function, these changes don't hold.
void Game::play() {
srand(time(NULL));
//Create vector
vector<vector<Room>> grid;
//Fill vector
fillGrid(grid);
//Set player and events
grid = setEvents(grid);
for (int i = 0; i < gridSize; i++) {
for (int j = 0; j < gridSize; j++) {
if (grid[i][j].getBoolEvent() == true) {
cout << i << " " << j << endl;
cout << grid[i][j].getEvent()->returnType() << endl;
}
}
}
}
As an output I get 0 0 and then a seg fault.
Although the boolEvent is still true, for some reason I get a segmentation fault when trying to call returnType(), even though it worked in the setEvents() function. What am I doing wrong with polymorphism?
This code isn't compiled. All problems in virtual function attack() in basic class.
It hasn't got acces to massive in class Team. I was trying do theese classes friend.But it do not work whatever. Also I've done function ptr but it don't work.
Virtual function don't work in inherited classes too. Visual studio 2015 shows errors:
C2228, C2227, C2027.
Please help.
class Team;
class Unit
{
protected:
int hp;
int dmg;
int doodge;
public:
Unit(int hp, int dmg, int doodge): hp(hp), dmg(dmg), doodge(doodge){}
int GetHP()
{
return hp;
}
void SetHP(int hp)
{
this->hp = hp;
}
virtual void attack(Team &T)
{
int id = rand() % 3;
for (int i = 0; i < 3; i++)
if (typeid(*this) == typeid(T.arr[i]))
{
id = i;
break;
}
if (T.arr[id] <= 0)
return;
else
T.arr[id]->SetHP(T.arr[id]->GetHP() - this->dmg);
}
};
class Swordsman:public Unit
{
public:
Swordsman():Unit(15,5,60){}
//virtual void attack(Team & T)override
//{
// int id = rand() % 3;
// for (int i = 0; i < 3; i++)
// if (typeid(Swordsman) == typeid())
// {
// id = i;
// break;
// }
// if (*T.arr[id]->GetHP <= 0)
// return;
// else
// *T.arr[id]->SetHP(T.arr[id]->GetHP() - dmg);
//}
};
class Archer :public Unit
{
public:
Archer() :Unit(12, 4, 40) {}
//virtual void attack(Team & T)override
//{
// int id = rand() % 3;
// for (int i = 0; i < 3; i++)
// if (typeid(Archer) == typeid())
// {
// id = i;
// break;
// }
// if (*T.arr[id]->GetHP <= 0)
// return;
// else
// *T.arr[id]->SetHP(T.arr[id]->GetHP() - dmg);
//}
};
class Mage :public Unit
{
public:
Mage() :Unit(8, 10, 30) {}
/*virtual void attack(Team & T)override
{
int id = rand() % 3;
for (int i = 0; i < 3; i++)
if (typeid(*this) == typeid())
{
id = i;
break;
}*/
};
class Team
{
static short counter;
string name;
Unit* arr[3];
public:
Team()
{
name = "Team " + counter++;
for (int i = 0; i < 3; i++)
{
int selecter = rand() % 3;
switch (selecter)
{
case 0:
arr[i] = new Swordsman();
break;
case 1:
arr[i] = new Archer();
break;
case 2:
arr[i] = new Mage();
break;
}
}
}
~Team()
{
delete[]arr;
}
Unit * ptr(int id)
{
return arr[id];
}
bool check()
{
bool res = false;
for (int i = 0; i < 3; i++)
if (arr[i]->GetHP() > 0)
res = true;
return res;
}
void print()
{
cout << endl << "\t\t" << name << endl << endl;
cout << "\t" << typeid(*arr[0]).name() << endl;
cout << "\t" << typeid(*arr[1]).name() << endl;
cout << "\t" << typeid(*arr[2]).name() << endl;
}
friend class Unit;
};
short Team::counter = 0;
class Game
{
Team A, B;
public:
int Play()
{
while (true)
{
A.ptr(1)->attack(B);
if (A.check())
return 1;
else if (B.check())
return 2;
}
}
};
int main()
{
return 0;
}
Omitting anything irrelevant:
class Team;
class Unit
{
public:
virtual void attack(Team &T)
{
if(typeid(*this) == typeid(T.arr[i]))
// ^^^
{ }
}
};
You are accessing a member of class Team, but at the time given, you only have provided the declaration of Team... Side note: this is not specific to virtual functions, but would occur with any code you write.
Your problem now is that function implementations of both classes Team as well as Unit rely on the complete definition of the other class. So only solution to the problem is to implement one of the functions outside the class, e. g.:
class Team;
class Unit
{
public:
// requires Team, so only declared, not implemented!
virtual void attack(Team &T);
// ^
};
class Team
{
// complete definition!
};
void Unit::attack(Team& t)
{
// now implementation of...
}
Another minor problem is that arr member is private. Well, you provided a getter already (ptr), so use it (and give it a better name...).
If you want to go further towards a clean design, split your units and the team into different compilation units, each coming with a header and a source file:
unit.h:
class Team;
class Unit
{
// private members
public:
// only declarations as above, including constructor/destructor
// by the way: you are lacking a virtual destructor!!!
virtual ~Unit();
};
unit.cpp:
#include "unit.h"
#include "team.h" // fetch the definition of Team!
Unit(/*...*/) { }
Unit::~Unit() { }
// function definitions as shown above...
You would do the same for Team and even your Unit derived classes as well as the Game class. Be aware, though, that you need the complete class definition available if you want to inherit, so you need to include unit.h already int the headers:
archer.h:
#include "unit.h"
class Archer : public Unit
{
// again, only function declarations...
// as base class has already a virtual destructor, own destructor
// gets virtual implicitly (even the default one), so if you do
// not need it, you do not have to define it...
};
archer.cpp:
#include "archer.h"
// and whatever else needed, solely, unit.h already comes with archer.h
// implementations...
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
My first question is: I am having a lot of trouble figuring out why the Example class is being constructed greater than the others. Below is a short app using a Template counter to track how many times the constructor/destructor/copy constructor is called for each class. There are a total of three classes: Example, Deep, Child. Each has a copy constructor... ugh.
Also, my second question, is what would be the correct way to define the copy constructor for the Child class?
In the printStatus(), it displays:
COUNTERS::NEW_COUNTER = 60
COUNTERS::DELETE_COUNTER = 50
COUNTERS::CONSTRUCTOR_COUNTER = 90
COUNTERS::DESTRUCTOR_COUNTER = 80
Example count = 10
Deep count = 0
Child count = 0
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
static unsigned cs_count_;
public:
Countable() { ++cs_count_; }
Countable( Countable const& ) { ++cs_count_; }
virtual ~Countable() { --cs_count_;}
static unsigned count() { return cs_count_; }
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
string a;
int b;
Example() {
COUNTERS::CONSTRUCTOR_COUNTER++;
a = "exampleString";
b = 5;
}
virtual ~Example() {
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Example(const Example& e) {
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = e.a;
this->b = e.b;
}
};
class Deep : public Countable<Deep>
{
public:
int a;
string b;
Example* e;
Deep()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
a = 3;
b = "deepString";
e = new Example();
COUNTERS::NEW_COUNTER++;
}
virtual ~Deep() {
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x)
{
COUNTERS::CONSTRUCTOR_COUNTER++;
this->a = x.a;
this->b = x.b;
this->e = new Example();
COUNTERS::NEW_COUNTER++;
this->e->a = x.e->a;
this->e->b = x.e->b;
};
};
class Child : public Countable<Child>
{
public:
Deep d;
string name;
int age;
Example* e;
vector<Example> list;
vector<Deep> deep_list;
void init()
{
Deep* var = new Deep(); COUNTERS::NEW_COUNTER++;
deep_list.push_back(*var);
delete var; COUNTERS::DELETE_COUNTER++;
}
Child() {
COUNTERS::CONSTRUCTOR_COUNTER++;
name = "a";
age = 10;
d.a = 1;
d.b = "deep";
d.e = NULL;
e = new Example();
COUNTERS::NEW_COUNTER++;
list.push_back(*e);
init();
}
virtual ~Child() {
COUNTERS::DESTRUCTOR_COUNTER++;
if(e != NULL) {
delete e;
COUNTERS::DELETE_COUNTER++;
}
}
// copy constructor
Child(const Child& c)
{
}
};
void myChildFunction(){
Child* c = new Child();
COUNTERS::NEW_COUNTER++;
delete c;
COUNTERS::DELETE_COUNTER++;
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for(unsigned int i=0 ; i < 10; i++)
myChildFunction();
printStatus();
return 0;
}
You are missing out on deleting some Example objects because of this line:
d.e = NULL;
in Child::Child().
You are allocating memory for e in the constructor of Deep. After executing the above line, that memory is leaked.
You can resolve that problem by:
Removing that line (or commenting it out),
Deleting d.e before making it NULL, or
Doing something else that prevents the memory leak.
Update, in response to comment
Copy constructor for Child:
Child(const Child& c) : d(c.d),
name(c.name),
age(c.age),
e(new Example(*c.e)),
list(c.list),
deep_list(c.deep_list)
{
COUNTERS::DESTRUCTOR_COUNTER++; // This is for Child
COUNTERS::NEW_COUNTER++; // This is for new Example
}
I removed all information that cluttered your code.
When using templates, constructors and copy constructors NEED the following: Example < eltType >(void);
in the class definition. All objects that inherit from Countables are known as derived classes. They also may call a derived class a child, and the class in which it is derived from is called the parent. I added the COPY_CONSTRUCTOR_COUNT to add clarification to the data which is being presented on the console/command prompt. Usually when trying to preform a task, large or small, doing it incrementally and by providing methods, for each task, saves you time and a headache. I removed the new_count and delete_count from the equation, because I felt that it was not needed.
You will notice that I added : Countable( * ((Countable < eltType > *)&e))
This is a requirement when designing a program that involves inheritance, which introduces the
topic of Polymorphism :D
What that bit of code does is that it gets a pointer of a Countable, which will point to the address of object e, which then allows access to all super classes of this class, but not including e's class.
NOTE: Since e is a derived class of Countable, this is valid statement.
For you second question, all of your data members are public, you can use an iterator to copy your data stored in you vectors.
As a concern from one programmer to another, I hope your code in practice is well documented, and all methods declared in your class are defined in a .cpp file.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class COUNTERS
{
public:
static int NEW_COUNTER;
static int DELETE_COUNTER;
static int CONSTRUCTOR_COUNTER;
static int DESTRUCTOR_COUNTER;
static int COPY_CONSTRUCTOR_COUNTER;
};
int COUNTERS::NEW_COUNTER = 0;
int COUNTERS::DELETE_COUNTER = 0;
int COUNTERS::CONSTRUCTOR_COUNTER = 0;
int COUNTERS::DESTRUCTOR_COUNTER = 0;
int COUNTERS::COPY_CONSTRUCTOR_COUNTER = 0;
/* template used for counting constructors/destructors to debug memory leaks */
template <typename T>
class Countable
{
public:
Countable<T>()
{
incrementObjectCount();
};
Countable<T>(Countable const&)
{
incrementObjectCount();
};
virtual ~Countable()
{
decrementObjectCount();
};
static unsigned count()
{
return cs_count_;
};
protected:
static unsigned cs_count_;
////////////////////////////////////ADDED////////////////////////////////////
protected:
void incrementObjectCount(void){ ++cs_count_; };
void decrementObjectCount(void){ --cs_count_; };
void incrementDeconstructorCounter(void){ ++COUNTERS::DESTRUCTOR_COUNTER; };
/////////////////////////////////////ADDED////////////////////////////////////
};
template <typename T>
unsigned Countable<T>::cs_count_ = 0;
class Example : public Countable<Example>
{
public:
Example() : Countable<Example>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Example()
{
incrementDeconstructorCounter();
}
// copy constructor
Example(const Example& e) : Countable<Example>(*((Countable<Example>*)&e))
{
// COUNTERS::CONSTRUCTOR_COUNTER++; This is copy constructor, you addmitted this from "Child" class CCstr
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
class Deep : public Countable<Deep>
{
public:
Deep() : Countable<Deep>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
}
virtual ~Deep()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Deep(const Deep& x) : Countable<Deep>(*((Countable<Deep>*)&x))
{
//COUNTERS::CONSTRUCTOR_COUNTER++;
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
};
};
class Child : public Countable<Child>
{
public:
vector<Example> list;
vector<Deep> deep_list;
void init()
{
deep_list.push_back(Deep());
list.push_back(Example());
}
Child() : Countable<Child>()
{
COUNTERS::CONSTRUCTOR_COUNTER++;
init();
}
virtual ~Child()
{
COUNTERS::DESTRUCTOR_COUNTER++;
}
// copy constructor
Child(const Child& c) : Countable<Child>(*((Countable<Child>*)&c))
{
++COUNTERS::COPY_CONSTRUCTOR_COUNTER; // For even more information added this
}
};
void myChildFunction(){
Child* c = new Child();
//COUNTERS::NEW_COUNTER++;not needed
delete c;
//COUNTERS::DELETE_COUNTER++; not need
}
void printStatus(){
cout << "COUNTERS::NEW_COUNTER = " << COUNTERS::NEW_COUNTER << endl;
cout << "COUNTERS::DELETE_COUNTER = " << COUNTERS::DELETE_COUNTER << endl;
cout << "COUNTERS::CONSTRUCTOR_COUNTER = " << COUNTERS::CONSTRUCTOR_COUNTER << endl;
cout << "COUNTERS::DESTRUCTOR_COUNTER = " << COUNTERS::DESTRUCTOR_COUNTER << endl;
cout << "COUNTERS::COPY_CONSTRUCTOR_COUNTER = " << COUNTERS::COPY_CONSTRUCTOR_COUNTER << endl;
cout << "Example count = " << Example::count() << endl;
cout << "Deep count = " << Deep::count() << endl;
cout << "Child count = " << Child::count() << endl;
}
int main()
{
for (unsigned int i = 0; i < 10; i++)
myChildFunction();
printStatus();
system("pause");
return 0;
}
The main question is how do I implement startTest() so that it calls runTest in all the subclasses. Thanks!
/*******************
COMPILER TEST
*******************/
class archeTest
{
protected:
short verbosity_;
public:
void setVerbosity(short v)
{
if( ((v == 1) || (v == 0) )
{
verbosity_ = v;
}
else
{
cout << " Verbosity Level Invalid " << endl;
}
}
virtual void runTest() = 0;
{
}
void startTest()
{
}
};
class testNatives : public archeTest
{
public:
void runTest()
{
testInts<short>();
testInts<int>();
testInts<long>();
testInts<unsigned short>();
testInts<unsigned int>();
testInts<unsigned long>();
}
void reportResults() const
{
}
protected:
template<class T> void testFloats()
template<class T> void testInts()
{
verbosity_ = 1;
T failMax;
short passState;
short bitDepth;
const char* a = typeid(T).name();
bool signedType = ((*a == 't') || (*a == 'j') || (*a == 'm'));
/* Bit Depth - Algorithm */
T pow2 = 1, minValue = 0, maxValue = 0, bitCount = 0, failValue = 0;
while(pow2 > 0)
{
pow2 *= 2;
maxValue = pow2-1;
bitCount++;
}
failValue = pow2;
int native1 = bitCount;
int native2 = sizeof(T)*8;
int native3 = numeric_limits<T>::digits;
if( !signedType )
{
native1++;
native3++;
}
if(verbosity_)
{
cout << endl << "**********\n" << reportType(a) << "\n**********" << endl << endl;
cout << "Bit Depth - Algorithm:\t" << native1 << endl;
cout << "Bit Depth - Sizeof:\t" << native2 << endl;
cout << "Bit Depth - File:\t" << native3 << endl;
}
if (native1 == native2 && native1 == native3)
{
cout << "Correlation:\t\tPass" << endl ;
}
else
{
cout << "Correlation:\t\tFail" << endl ;
}
cout << "Max Value:\t\t" << maxValue << endl;
cout << "Max+1 Value:\t\t" << failValue << endl;
}
string reportType(const char* c1)
{
string s1;
switch(*c1)
{
case 't':
s1 = "Unsigned short";
break;
case 'j':
s1 = "Unsigned int";
break;
case 'm':
s1 = "Unsigned long";
break;
case 's':
s1 = "Short";
break;
case 'i':
s1 = "Int";
break;
case 'l':
s1 = "Long";
break;
default:
s1 = "Switch failed";
}
return s1;
}
};
int main()
{
testNatives A;
A.runTest();
}
It is possible but to do it you will have to use an abstract factory pattern. Please read this for an overview on what the abstract pattern is and how it can do what you need.
If you can use boost in your project then you can implement your own abstract factory by using the boost::factory template.
There are a lot of other implementations for the abstract factory that you might be able to use if you do not want to roll out your own. Here is a link to one such implementation.
EDIT: In this case you will also need some mechanism to register new test cases with the factory at compile time. This can be achieved by leveraging either c++ preprocessor or templates. Here is an approach for this that uses templates.
Well, first - single responsibility principle. That in mind, your archeTest shouldn't manage alle test objects. Just have an (in)famous Manager do that!
#include <vector>
class TestManager{
std::vector<archeTest*> _tests;
public:
// either
void AddTest(archeTest* test){
_tests.push_back(test);
}
// OR
archeTest* CreateTest(/*here_be_params*/){
archeTest* test = new archeTest(/*params*/);
// do whatever
_tests.push_back(test);
return test;
}
void RunAllTests() const{
for(int i=0; i < _tests.size(); ++i)
_tests[i]->runTests();
}
// if you create tests in here, you also need to release them at the end
// ONLY do this if your created the tests with CreateTest
// or if you transfer the ownership of the test pointer to TestManager
~TestManager(){
for(int i=0; i < _tests.size(); ++i)
delete _tests[i];
}
};
Run with
TestManager tmgr;
// create all your tests, either with
// archeTest* p = tmgr.CreateTest();
// OR
// archeTest* p = new archeTest();
// tmg.AddTest(p);
// and then run with
tmgr.RunAllTests();
Again, see the comments in the TestManager implementation.
Now, if you really really don't want an extra class ... that is actually easier, but it's kinda code smell. Just add your class in the constructor of archeTest into a static linked list - problem solved! Remove it on destruction again of course. This works because every derived class xxxstructor automatically calls the base class version - the *con*structor before its own and the *de*structor after its own:
#include <list>
class archeTest{
private:
typedef std::list<archeTest*> TestList;
static TestList _all_tests;
// to erase the right test on destruction
TestList::iterator _this_test;
public:
archeTest(){
_all_tests.push_back(this);
}
~archeTest(){
_all_tests.erase(_this_test);
}
static void RunAllTests(){
for(TestList::iterator it = _all_tests.begin(); it != _all_tests.end(); ++it)
(*it)->runTests();
}
};
// in some TestManager.cpp
#include "TestManager.h"
TestManager::TestList TestManager::_all_tests;
Run it with a simple
// create all your tests;
// ...
archeTest::RunAllTests();
since it's a static member function, it doesn't need an instance.;
Note that I used a linked list, as that allows me to safely remove a test in the middle of the list without invalidating the references stored in the other test objects.
Since a lot of people were finding it difficult to follow through all the posts I listed. I implemented a version of this using boost.
The trick is the fact that when the definition for TestTemplate is expanded with the derived class definitions(new Test cases) it forces a call to the TestManager::Register method due to the initialization of the static const.
template<typename TestCase>
const unsigned Test<TestCase>::m_uTestID = TestManager::Register(boost::factory<TestCase*>());
This ensures that a functor to the constructor of the derived class is stored in the TestManager's map. Now in the TestManager I simply iterate over the map and use the functor to instantiate each Testcase and call the run method on the newly created instance.
Any class that is derived from the TestTemplate will be registered automatically, No need to manually list all of them.
#include <map>
#include <iostream>
#include <boost/function.hpp>
#include <boost/functional/factory.hpp>
class ITest {
public:
virtual void run() {
runTest();
}
virtual void runTest() = 0;
};
typedef boost::function< ITest* ()> TestFactory;
class TestManager {
public:
static int Register(TestFactory theFactory) {
std::cout<<"Registering Test Case"<<std::endl;
m_NumTests++;
m_mapAllTests[m_NumTests] = theFactory;
return m_NumTests;
}
void run() {
for(unsigned uTestID = 1; uTestID <= m_NumTests; uTestID++) {
ITest* theTestCase = m_mapAllTests[uTestID]();
theTestCase->run();
delete theTestCase;
}
}
private:
static unsigned m_NumTests;
static std::map<unsigned, TestFactory> m_mapAllTests;
};
unsigned TestManager::m_NumTests = 0;
std::map<unsigned, TestFactory> TestManager::m_mapAllTests;
template<typename TestCase>
class Test : public ITest {
public:
unsigned getID() const {
return m_uTestID;
}
private:
static const unsigned m_uTestID;
};
template<typename TestCase>
const unsigned Test<TestCase>::m_uTestID = TestManager::Register(boost::factory<TestCase*>());
class Test1 : public Test<Test1> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test2 : public Test<Test2> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test3 : public Test<Test3> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
class Test4 : public Test<Test4> {
public:
virtual void runTest() {
std::cout<<"Test Id:"<<getID()<<std::endl;
}
};
int main() {
TestManager theManager;
theManager.run();
}
I did test the solution on VS05 and VS10. Below is the expected output.
Registering Test Case
Registering Test Case
Registering Test Case
Registering Test Case
Test Id:1
Test Id:2
Test Id:3
Test Id:4
Hope it clears up some confusion.
First off, you would declare startTest like this in archeTest.
virtual void startTest() = 0;
That makes it a pure virtual function that must be implemented in child classes. To call this method on a child class, you must have an object of that particular class instantiated. Then you can call startTest either through a base class pointer or through a pointer to the child class. Note that in either case the pointer must be pointing to an instantiation (concrete object) of the child class.
You might want to check out UnitTest++ (you can browse the source code here). Pay particular attention to TestMacros.h and CheckMacros.h, which, as their names imply, implement macros to automatically collect and run tests.
The following code, for example, is "a minimal C++ program to run a failing test through UnitTest++."
// test.cpp
#include <UnitTest++.h>
TEST(FailSpectacularly)
{
CHECK(false);
}
int main()
{
return UnitTest::RunAllTests();
}
You can read more at the (brief) UnitTest++ overview. I haven't delved into the details of how the TEST and CHECK macros are implemented, but they do allow you to declare tests in many different CPP files and then run them all via a single call to UnitTest::RunAllTests(). Perhaps this is close enough to what you want to do?
EDIT: never mind, my first answer didn't make any sense. In C++, you cannot obtain the list of all subclasses of a class to instantiate them, so I don't think you can implement runTests() the way you want it.