I have a class like this:
class SelectorFactory
{
public:
static std::map<std::string,int> _creator;
static void registerCreator(std::string& name,int value)
{
//static std::map<std::string,int> _creator;
if(_creator.end() != _creator.find(name))
{
std::cout << "Selector already registered \n";
}
else
{
std::cout << "Entering " <<name<<" in register: \n";
_creator[name]=value;
}
}
static int createSelector(std::string selectorName)
{
//static std::map<std::string,int> _creator;
std::map< std::string , int >::iterator mapIter=_creator.find(selectorName);
if(mapIter==_creator.end())
{
std::cout<<selectorName<<" Not found in the Map \n" ;
return 0;
}
else
{
int selector= mapIter->second;
return selector;
}
}
};
If I uncomment the commented lines above, code is getting compiled but it's not returning any value from createSelector function which is quite obvious.But if I keep them commented, I am getting error as "_creator was not declared in this scope" inside both the functions.
What should I do to rectify this issue.
In order to have -creator instantiated, you must provide a definition for it. Currently, you have only a declaration.
class SelectorFactory
{
static std::map<std::string,Int> _creator;
};
std::map<std::string,Int> SelectorFactory::_creator;
SelectorFactory.h :
#ifndef __SELECTOR_FACTORY__H__
#define __SELECTOR_FACTORY__H__
#include <string>
#include <map>
class SelectorFactory
{
public:
static void registerCreator(std::string& name,int value);
static int createSelector(std::string selectorName);
private: // !!!!!!!!! NOT PUBLIC!!! >:(
static std::map<std::string,int> _creator;
};
#endif // __SELECTOR_FACTORY__H__
SelectorFactory.cpp :
#include "SelectorFactory.h"
#include <iostream>
std::map<std::string,int> SelectorFactory::_creator;
void SelectorFactory::registerCreator(std::string& name,int value)
{
if(_creator.end() != _creator.find(name))
{
std::cout << "Selector already registered \n";
}
else
{
std::cout << "Entering " <<name<<" in register: \n";
_creator[name]=value;
}
}
int SelectorFactory::createSelector(std::string selectorName)
{
std::map< std::string , int >::iterator mapIter=_creator.find(selectorName);
if(mapIter==_creator.end())
{
std::cout<<selectorName<<" Not found in the Map \n" ;
return 0;
}
else
{
int selector= mapIter->second;
return selector;
}
}
Related
I am trying to insert a set of pair values into a std::map in c++11. However, the values don't seem to insert into the std::map. Please do go over my code about the same. I appreciate any and all help.
#include<iostream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<cstdlib>
#include<utility>
#include<ctime>
#include "print.h"
class ReportCard
{
private:
std::map<std::string, double> m_report_card;
public:
std::map<std::string, double> getReportCardInstance() { return m_report_card; }
};
class Student
{
private:
int m_roll_no;
std::string m_name;
ReportCard m_reportCard;
public:
Student(int inRollNo, const std::string& inName) :
m_roll_no(inRollNo), m_name(inName)
{}
std::string getName() { return m_name; }
int getRollNo() { return m_roll_no; }
ReportCard getReportCard() { return self.m_reportCard; }
int getReportCardSize() { return m_reportCard.getReportCardInstance().size(); }
};
class Driver
{
private:
std::vector<Student> student_list;
std::vector<Student> temp;
public:
void studentTestPopulate()
{
student_list.push_back(Student(1, "Tim"));
student_list.push_back(Student(2, "Matt"));
student_list.push_back(Student(100, "Luke"));
student_list.push_back(Student(68, "Lissy"));
student_list.push_back(Student(20, "Tony"));
student_list.push_back(Student(33, "Joseph"));
student_list.push_back(Student(14, "Sid"));
student_list.push_back(Student(15, "Roby"));
student_list.push_back(Student(44, "Rohan"));
student_list.push_back(Student(11, "Kevin"));
student_list.push_back(Student(19, "George"));
}
void reportCardPopulate()
{
for (auto& student : student_list)
{
std::cout << student.getName() << std::endl;
student.getReportCard().getReportCardInstance().insert(std::make_pair<std::string, double>("Math", generateMark));
//This is the function that does not work. No marks are printed!!
for (auto& mark : student.getReportCard().getReportCardInstance())
{
std::cout << mark.first << " " << mark.second;
}
//student.getReportCard().getReportCardInstance().insert(std::make_pair("Science", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("Geography", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("French", generateMark));
//student.getReportCard().getReportCardInstance().insert(std::make_pair("History", generateMark));
}
}
void showAllStudentDetails()
{
for (auto& student : student_list)
{
std::cout << student.getName() << std::endl;
std::cout << student.getRollNo() << std::endl;
std::cout << "REPORT CARD : " << student.getReportCardSize() << std::endl << std::endl;
for (auto& mark : student.getReportCard().getReportCardInstance())
{
std::cout << mark.first << std::endl;
std::cout << mark.second << std::endl;
}
}
}
};
int main()
{
srand(time(NULL));
Driver driver;
driver.studentTestPopulate();
driver.reportCardPopulate();
//driver.showAllStudentDetails();
}
The reportCardPopulate() function is supposed to insert pairs of values into a report_card map. However, the insert function doesn't seem to work.
When we try to print the values within the reportCardPopulate() function, it doesn't print anything. When I try to print the size of the map, it prints 0. When I printed the size using sizeof() it prints the same size before and after the insertion.
The following functions
std::map<std::string, double> getReportCardInstance() { ... }
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
ReportCard getReportCard() { ... }
//^^^^^^^^
returns the copy of std::map<std::string, double> and ReportCard class respectively. Therefore, whatever you insert here
student.getReportCard().getReportCardInstance().insert(std::make_pair<std::string, double>("Math", generateMark));
does on the copies of the above, hence the original member in ReportCard(i.e. m_report_card) will never get be updated. After the call of above line, the copies will be destroyed and expecting it to work make no sense.
Secondly, shown code is wrong, because in c++ you should have used this not self
ReportCard getReportCard()
{
return self.m_reportCard;
//^^^^ --> should be `return this->m_reportCard;`
// or simply `return m_reportCard;`
}
Correcting the above, and returning the member by reference will make the code work.
(See live online)
std::map<std::string, double>& getReportCardInstance()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^
{
return m_report_card;
}
ReportCard& getReportCard()
//^^^^^^^^
{
return m_reportCard;
}
That being said, your ReportCard and Student classes will expose the members, if you do the above. Which is not a good design. If those are meant only for the internal uses of Driver class, you could keep them as private properties of Driver class.
#include <vector>
#include <map>
#include <string>
#include <iostream>
class Driver /* final */ // -> optional
{
private: // Student is private for Driver class
class Student
{
// type alias is enough for the map
using ReportCard = std::map<std::string, double>;
private:
int m_roll_no;
std::string m_name;
ReportCard m_reportCard;
public:
Student(int inRollNo, const std::string& inName)
: m_roll_no{ inRollNo }, m_name{ inName }
{}
// make the member functions const if they are not modifing the members
const std::string& getName() const { return m_name; }
int getRollNo() const { return m_roll_no; }
ReportCard& getReportCard() { return m_reportCard; }
std::size_t getReportCardSize() const { return m_reportCard.size(); }
};
private:
std::vector<Student> student_list;
std::vector<Student> temp;
public:
void studentTestPopulate()
{
// construct the `Student` in-place using `std::vector::emplace_back`
student_list.emplace_back(1, "Tim");
student_list.emplace_back(2, "Matt");
student_list.emplace_back(100, "Luke");
student_list.emplace_back(68, "Lissy");
student_list.emplace_back(20, "Tony");
student_list.emplace_back(33, "Joseph");
student_list.emplace_back(14, "Sid");
student_list.emplace_back(15, "Roby");
student_list.emplace_back(44, "Rohan");
student_list.emplace_back(11, "Kevin");
student_list.emplace_back(19, "George");
}
void reportCardPopulate()
{
for (auto& student : student_list)
{
std::cout << student.getName() << "\n";
student.getReportCard().emplace(student.getName(), 12.0);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// use `std::map::emplace` for constructing `ReportCard` in-place
for (auto& mark : student.getReportCard())
{
std::cout << mark.first << " " << mark.second << "\n";
}
}
}
// ... other members
};
int main()
{
Driver driver;
driver.studentTestPopulate();
driver.reportCardPopulate();
}
#include <iostream>
#include <map>
class ReportCard
{
//private: this is the default anyway for a class
public: //made to be able to print the internals below.
std::map<std::string, double> m_report_card;
public:
/* this returns an instance of the std::map. The map is copied and
returned, so any modifications will not affect m_report_card
std::map<std::string, double> getReportCardInstance()
{
return m_report_card;
}
if you want to do this, return std::map<std::string, double>&.
std::map<std::string, double>& getReportCardInstance()
{
return m_report_card;
}
*/
// better solution is to have a method to add the report
void add_report(const std::string& first,double second)
{
m_report_card[first] = second;
}
};
int main() {
ReportCard rc;
rc.add_report("Percy",1.0);
rc.add_report("Pig",2.0);
for(auto internal_report_card : rc.m_report_card)
{
std::cout << internal_report_card.first << ", "
<< internal_report_card.second << std::endl;
}
return 0;
}
Demo
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();
}
http://ideone.com/1ohrsO
The push_back called inside the constructor of static_constructor, is not reflected. Why?
#include <iostream>
#include <vector>
#include<memory>
#include<string>
using namespace std;
class has_static_constructor
{
public:
friend class static_constructor;
static vector<int> v;
class static_constructor
{
public:
vector<int> * upt; //&v;
static_constructor()
{
cout<<"inside static_constructor";
upt = &has_static_constructor::v;
has_static_constructor::v.push_back(1);
has_static_constructor::v.push_back(20);
}
} ;
static std::unique_ptr<has_static_constructor::static_constructor> upt ;
};
unique_ptr<has_static_constructor::static_constructor> has_static_constructor::upt(new has_static_constructor::static_constructor());
vector< int > has_static_constructor::v(2,100);
int main() {
// your code goes here
for (std::vector<int>::const_iterator i = has_static_constructor::v.begin(); i != has_static_constructor::v.end(); ++i)
{ std::cout << *i << ' ';
cout<<"\n I was here\n";
}
return 0;
}
Output:
inside static_constructor100
I was here
100
I was here
static_constructor() is called before has_static_constructor::v initialization.
Move
unique_ptr<has_static_constructor::static_constructor> has_static_constructor::upt(new has_static_constructor::static_constructor());
after
vector< int > has_static_constructor::v(2,100);
to have expected behaviour.
But better avoid those global entirely.
You might want to have a look at this way of ordering the code. It removes all initialisation-order dependencies, and in my view neatly separates the public interface from the internal implementation of the static data.
#include <iostream>
#include <vector>
class has_static_constructor
{
// note - all private
struct static_data {
static_data()
: _v(2, 100)
{
_v.push_back(1);
_v.push_back(20);
}
std::vector<int> _v;
};
static static_data& statics() {
static static_data sd;
return sd;
}
// public interface
public:
static std::vector<int>& v() { return statics()._v; }
};
auto main() -> int
{
for (const auto& i : has_static_constructor::v())
{
std::cout << i << std::endl;
}
return 0;
}
expected output:
100
100
1
20
I'll go straight to an example, I think it is easier to underestand.
Music Cd has Tracks. How can I access A TrackInfo vector (XTrackInfo) data "inside" Music Cd class?
I want to print and even change values, I don't figure out how.
Thanks
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <iterator>
#include <numeric>
class XTrackInfo
{
std::string m_TrackName;
int m_Length;
public:
XTrackInfo() {}
XTrackInfo(std::string TrackName, int Length):
m_TrackName(std::move(TrackName)),
m_Length(Length)
{}
void SetTrackName(std::string TrackName) { m_TrackName = std::move(TrackName); }
void SetTrackLength(int Length) { m_Length = Length; }
const std::string& GetTrackName() const { return m_TrackName; }
int GetTrackLength() const { return m_Length; }
};
class XMusicCd
{
private:
std::string m_Author;
std::vector<XTrackInfo> m_TrackInfo;
public:
XMusicCd() {}
XMusicCd(std::string Author, std::vector<XTrackInfo> Tracks):
m_Author(std::move(Author)),
m_TrackInfo(std::move(Tracks))
{}
void SetAuthor(std::string Author) { m_Author = std::move(Author); }
const std::string& GetAuthor() const { return m_Author; }
const std::vector<XTrackInfo> GetTracks() const { return m_TrackInfo;}
int GetLength() const; // Left incomplete on purpose; you will implement it later
void AddTrack(XTrackInfo NewTrack){
m_TrackInfo.emplace_back(std::move(NewTrack));
}
};
void PrintCdContents(const XMusicCd& Cd)
{
std::cout << "Author : " << Cd.GetAuthor() << "\n";
std::cout << "\n" << std::endl;
std::cout << "Track Info" << std::endl;
//problems here :)
}
int main()
{
// You may not change this function
XMusicCd MyCd;
MyCd.SetAuthor("Hello World");
MyCd.AddTrack(XTrackInfo("This is a test", 100));
MyCd.AddTrack(XTrackInfo("This is a test 2", 200));
PrintCdContents(MyCd);
}
Use iterators:
std::vector<XTrackInfo> tracks = Cd.GetTracks();
for (std::vector<XTrackInfo>::const_iterator it = tracks.begin(); it != tracks.end(); ++it) {
std::cout << it->GetTrackName() << std::endl;
}
Or indexes:
std::vector<XTrackInfo> tracks = Cd.GetTracks();
for (unsigned i = 0; i < tracks.size(); ++i) {
std::cout << tracks.at(i).GetTrackName() << std::endl;
}