This question already has answers here:
When should static_cast, dynamic_cast, const_cast, and reinterpret_cast be used?
(11 answers)
Closed 9 years ago.
What would be a genuinely-acceptable example of usage for a derived cast? I have always thought they are only used when implementing "hacks" but if this is not the case, could someone give an acceptable example of when to use one?
#user997112
[edit at bottom]
Hello. Below we use a collection of random polymorphic pointers with common ancestor
through the common interface.
Additional work is done with one of the particular derived classes
we need dynamic_cast or typeid to know this ....
main function has the call
then class declarations
then the dynamic cast is at end
delete of objects created with new is not shown
#include <iostream>
#include <algorithm>
#include <random>
#include <exception>
using namespace std;
int dynamic_test();
int main()
{
cout << "Hello world!" << endl;
dynamic_test();
return 0;
}
............
class basex {
public:
virtual ~basex() {};
virtual void work() const = 0;
};
class next1x : public basex {
public:
void work() const override {cout << "1";/*secret*/}
};
class next2x : public basex {
public:
void work() const override {cout << "2";/*secret*/}
};
class next3x : public basex {
public:
void work() const override {cout << "3";/*secret*/}
};
std::vector<basex *> secret_class_picker()
{
//pick classes with common base at random
std::random_device rd;
std::uniform_int_distribution<int> ud(1,3);
std::mt19937 mt(rd());
std::vector<int> random_v;
for (int i = 0; i < 22; ++i)
random_v.push_back( ud(mt) );
cout << "Random" << endl;
for ( auto bq : random_v) //inspecting for human reader
cout << bq << " ";
std::vector<basex *> v;
basex * bptr;
for (auto bq : random_v) {
switch(bq)
{
default: throw std::exception(); break;
case 1: bptr = new next1x; break;
case 2: bptr = new next2x; break;
case 3: bptr = new next3x; break;
}
v.push_back(bptr);
}
cout << "Objects Created " << v.size() << endl;
return v;
}
//this function demands a more derived class
int special_work(const next3x *)
{
//elided
cout <<"[!]";
return 0;
}
int dynamic_test()
{
std::vector<basex *> v = secret_class_picker();//delete these pointer later
cout <<"Working with random polymorphic pointers"<<endl;
for (const auto bq : v)
{
bq->work();//polymorphic
next3x * ptr = dynamic_cast<next3x *>(bq);
if (nullptr != ptr) special_work(ptr); //reserved for particular type
}
return 0;
}
...................... alternative
int dynamic_static_typeid()
{
std::vector<basex *> v = secret_class_picker();
cout <<"Working with random polymorphic pointers"<<endl;
int k(0);
for (const auto bq : v)
{
bool flipflop = (k % 2) == 0;
bq->work();//polymorphic
//cout << "[*]"<< typeid(*bq).name();//dereference
if (flipflop) {
next3x * dc_ptr = dynamic_cast<next3x *>(bq);//not constant time in general
if (nullptr != dc_ptr) {
special_work(dc_ptr); //reserved for particular type
++k;
}
}
else {
if (typeid(next3x) == typeid(*bq)){//constant time
auto sc_ptr = static_cast<next3x *>(bq);//constant time
special_work(sc_ptr);
++k; cout <<"[sc]";
}
}
cout << endl;
}
return 0;
}
Related
I am training to my exam in c++ and I don't understand why the code display only print function of the base class (also after I debug the code) and never go to the print of derived class.
Can you explain me why in a simple way, and does there is some issue I can do in order to also display the print function of derived class only by edit a few line of code.
Let say the number that the program generate are: 1 67 0 69 0 0 58 78.
class A
{
int a;
public:
A(int x):a(x){}
void print() { cout << "a=" << a << ' '; }
};
class B:public A
{
int b;
public:
B(int x,int y) :A(x),b(y) {}
void print() { A::print(); cout << "b=" << b << ' '; }
};
int main(){
list<A*> lst;
for (int i = 0; i < 3; i++)
if(rand()%2)
lst.push_back(new A(rand() % 100));
else
lst.push_back(new B(rand() % 100,rand()%100));
for (list<A*>::iterator it = lst.begin(); it != lst.end(); it++)
(*it)->print();
}
You need to declare print() virtual in order for polymorphism to work.
Here is your example with suggested formatting improvements,
#include <iostream>
#include <list>
class A{
int a;
public:
A(int x):a(x){}
virtual void print() { std::cout << "a=" << a << ' '; }
};
class B:public A{
int b;
public:
B(int x,int y) :A(x),b(y) {}
void print() override { A::print(); std::cout << "b=" << b << ' '; }
};
int main(){
std::list<A*> lst;
for (int i = 0; i < 30; i++) {
if(rand()%2) {
lst.push_back(new A(rand() % 100));
} else {
lst.push_back(new B(rand() % 100,rand()%100));
}
}
for (std::list<A*>::iterator it = lst.begin(); it != lst.end(); it++) {
(*it)->print();
}
}
I increased the number of printed elements, because in these settings I wasn't getting a single b. This said:
You need to seed your code with srand if you don't want to get the same numbers over and over again (and you need to seed it only once per program).
If possible, you should use the new random number generation functionality available from C++11 on.
override is optional, but very encouraged, it clearly signals that the function was virtual and re-implemented.
Most importantly you need to free the memory you allocated with new (using delete), or better yet, use the approach in #TedLyngmo answer (smart pointers)
In order to make use of dynamic dispatch, you need to make A::print() virtual. You also need to make A's destructor virtual to be able to delete objects through the base class pointer.
Since you currently do not delete any objects (but instead leak all A's and Bs) I suggest that you make use of a smart pointer, std::unique_ptr<A>, that will clean up when the std::list is destroyed.
Example:
#include <iostream>
#include <list>
#include <memory> // std::unique_ptr
class A {
int a;
public:
A(int x) : a(x) {}
virtual ~A() = default; // virtual destructor
virtual void print() { std::cout << "a=" << a << ' '; }
};
class B : public A {
int b;
public:
B(int x, int y) : A(x), b(y) {}
void print() override {
A::print();
std::cout << "b=" << b << ' ';
}
};
int main() {
std::list<std::unique_ptr<A>> lst; // use of smart pointer
for(int i = 0; i < 30; i++) {
if(rand() % 2) {
lst.emplace_back(std::make_unique<A>(rand() % 100));
} else {
lst.emplace_back(std::make_unique<B>(rand() % 100, rand() % 100));
}
}
for(auto it = lst.begin(); it != lst.end(); it++) {
(*it)->print();
}
// Simpler loop: A range-based for loop:
// for(auto& ptr : lst) ptr->print();
}
Error
e/c++/v1/algorithm:642:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/utility:321:9: error:
field type 'Space' is an abstract class
_T2 second;
^
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/map:624:16: note:
Question
How can I define a std::vector of type Space which is an abstract class and then fill this vector with instances of the derived classes Empty, Snake, Ladder.
Context
I know abstract classes in C++ can not be instantiated. Instead I've read in several posts on this and other sites that you can create a collection of an abstract type if it the type is defined as a star * pointer or any of the <memory> managed pointer data types like std::unqiue_ptr<T>. I've tried to used shared_ptr<Space> in my case, but still unable to define the collection properly. I am compiled my code using g++ -std=c++17 main.cpp && ./a.out.
Code
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <map>
#include <memory>
#include <typeinfo>
#include <queue>
#include <string>
#include <vector>
class Player
{
private:
int m_current_space = 1;
public:
Player() {}
void role_dice() {
m_current_space += floor( (rand()%10 + 1) / 3 );
}
int const get_current_space() {
return m_current_space;
}
void set_current_space(int current_space) {
m_current_space = current_space;
}
};
class Space
{
protected:
int m_id;
std::vector<Space> m_paths;
public:
Space() {} // requied to use [] operator in map
Space(int id) : m_id(id) {}
void add_path(Space& s) {
m_paths.push_back(s);
}
int get_id() {
return m_id;
}
virtual std::string class_type() = 0;
};
class Empty : public Space
{
public:
Empty(int id) : Space(id) {}
std::string class_type() {
return "Empty";
}
};
class Ladder : public Space
{
public:
Ladder(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(1);
}
std::string class_type() {
return "Ladder";
}
};
class Snake : public Space
{
public:
Snake(int id) : Space(id) {}
virtual void event(Player& p) {
p.set_current_space(4);
}
std::string class_type() {
return "Snake";
}
};
class Board
{
private:
std::map<int, Space> m_board;
public:
void add_space(Space& s) {
m_board[s.get_id()] = s;
}
void draw_board() {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
std::cout << "○\n";
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
std::cout << "○ ";
}
++i;
}
}
void update_player_on_board(int position) {
int i = 1;
for(auto const& [space_key, space] : m_board) {
if(i%3 == 0) {
if (space_key == position) {
std::cout << "●\n";
}
else {
std::cout << "○\n";
}
}
else if(typeid(space) == typeid(Snake)) {
std::cout << "○-";
}
else {
if (space_key == position) {
std::cout << "● ";
}
else {
std::cout << "○ ";
}
}
++i;
}
}
const std::map<int, Space> get_board() {
return m_board;
}
friend std::ostream &operator<<(std::ostream& os, const Board& b) {
return os;
}
};
class GameStateManager
{
private:
std::string m_state = "game over";
bool m_playing = false;
public:
std::string const get_state() {
return m_state;
}
void set_state(std::string state) {
m_state = state;
}
};
int main()
{
std::cout << "Welcome to Bowser's 9 board game\n";
std::cout << "Start? y(yes) n(no)\n";
GameStateManager game_manager;
game_manager.set_state("playing");
auto space1 = std::make_shared<Space>(1);
auto space2 = std::make_shared<Space>(2);
auto space3 = std::make_shared<Space>(3);
auto space4 = std::make_shared<Space>(4);
auto space5 = std::make_shared<Space>(5);
auto space6 = std::make_shared<Space>(6);
auto space7 = std::make_shared<Space>(7);
auto space8 = std::make_shared<Space>(8);
auto space9 = std::make_shared<Space>(9);
std::vector<std::shared_ptr<Space>> v {
space1, space2, space3,
space4, space5, space6,
space7, space8, space9
};
Board bowsers_bigbad_laddersnake;
for(int i = 0; i < 10; ++i) {
bowsers_bigbad_laddersnake.add_space(*(v[i]));
}
bowsers_bigbad_laddersnake.draw_board();
Player mario;
int turn = 0;
while(game_manager.get_state() == "playing") {
std::cin.get();
std::cout << "-- Turn " << ++turn << " --" << '\n';
mario.role_dice();
bowsers_bigbad_laddersnake.update_player_on_board(mario.get_current_space());
if (mario.get_current_space() >= 9) {
game_manager.set_state("game over");
}
}
std::cout << "Thanks a so much for to playing!\nPress any key to continue . . .\n";
std::cin.get();
return 0;
}
You seem to have removed a lot of code to get into details here.
Have a Space pointer (smart or raw). Instantiate the specific space that you want, point to it with your pointer of type Space. Example std::shared_ptr<Space> pointerToSpace = std::make_shared<Snake> ("I'm a snake"); Now, without loss of generality, you can print the contents (of concrete type) with just the pointer to the space pointerToSpace->class_type(). Yes, you can have a collection of shared_ptrs in a container.
I am trying to implement observer design pattern in C++ as below
#include <iostream>
#include <vector>
using namespace std;
class observer
{
public:
observer() = default;
~observer() = default;
virtual void notify() = 0;
};
class subject
{
vector <observer *> vec;
public:
subject() = default;
~subject() = default;
void _register(observer *obj)
{
vec.push_back(obj);
}
void unregister(observer *obj)
{
int i;
for(i = 0; i < vec.size(); i++)
{
if(vec[i] == obj)
{
cout << "found elem. unregistering" << endl;
vec.erase(vec.begin() + i);
break;
}
}
if(i == vec.size())
{
cout << "elem not found to unregister" << endl;
}
}
void notify()
{
vector <observer *>::iterator it = vec.begin();
while(it != vec.end())
{
(*it)->notify();
it ++;
}
}
};
class obsone : public observer
{
void notify()
{
cout << "in obsone notify" << endl;
}
};
class obstwo : public observer
{
void notify()
{
cout << "in obstwo notify" << endl;
}
};
int main()
{
subject sub;
obsone *one = new obsone();
obstwo *two = new obstwo();
sub._register(one);
sub._register(two);
sub.notify();
sub.unregister(one);
sub.notify();
//delete two;
//sub.notify();
return 0;
}
I am registering the objects with the subject explicitly. Is it the correct way of doing it or do I need to register through observer class only. Are there any problems with the above approach?
Here's an example of doing the callbacks with lambdas and function objects in the callback collection.
The details can vary greatly! So, this code is not “the” way, but just your code rewritten in one specific way, out of a myriad possibilities. But it hopefully shows the general idea in modern C++.
#include <iostream>
#include <functional> // std::function
#include <stdint.h> // uint64_t
#include <unordered_map> // std::unordered_map
#include <utility> // std::move
#include <vector> // std::vector
using namespace std;
namespace my
{
using Callback = function<void()>;
template< class Key, class Value > using Map_ = unordered_map<Key, Value>;
class Subject
{
public:
enum Id: uint64_t {};
private:
Map_<uint64_t, Callback> m_callbacks;
static auto id_value()
-> uint64_t&
{
static uint64_t the_id;
return the_id;
}
public:
auto add_listener( Callback cb )
-> Id
{
const auto id = Id( ++id_value() );
m_callbacks.emplace( id, move( cb ) );
return id;
}
auto remove_listener( const Id id )
-> bool
{
const auto it = m_callbacks.find( id );
if( it == m_callbacks.end() )
{
return false;
}
m_callbacks.erase( it );
return true;
}
void notify_all() const
{
for( const auto& pair : m_callbacks )
{
pair.second();
}
}
};
}
struct Observer_1
{
void notify() { cout << "Observer_1::notify() called." << endl; }
};
struct Observer_2
{
void notify() { cout << "Observer_2::notify() called." << endl; }
};
auto main()
-> int
{
my::Subject subject;
Observer_1 one;
Observer_2 two;
using Id = my::Subject::Id;
const Id listener_id_1 = subject.add_listener( [&]{ one.notify(); } );
const Id listener_id_2 = subject.add_listener( [&]{ two.notify(); } );
cout << "After adding two listeners:" << endl;
subject.notify_all();
cout << endl;
subject.remove_listener( listener_id_1 )
and (cout << "Removed listener 1." << endl)
or (cout << "Did not find registration of listener 1." << endl);
cout << endl;
cout << "After removing or attempting to remove listener 1:" << endl;
subject.notify_all();
}
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.