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 3 years ago.
Improve this question
I have declared a function bool Network::areFriends(User & usr1, User & usr2) which when called unfortunately I am met with
identifier "function_name" is undefined
And the classes in which I am referring to.
Wall.h
#pragma once
class Wall
{
private:
std::list<Message> msgs_posted;
User* w_owner;
public:
Wall() = delete;
Wall(User* wownr);
virtual ~Wall();
void postMsg(User& usr ,Message msg);
void toString();
std::list<Message> getMsgsPosted();
};
Wall.cpp
#include "pch.h"
#include <iostream>
Wall::Wall(User * wownr)
:w_owner(wownr)
{
}
Wall::~Wall()
{
}
void Wall::postMsg(User& usr, Message msg)
{
//if are friends
if ((usr == *this->w_owner) || areFriends(usr,*this->w_owner)){
msgs_posted.push_back(msg);
/* does it get copied altogether? */
}
else
std::cout << "You can not post at this person's wall." << std::endl;
}
void Wall::toString()
{
std::list<Message> ::iterator tmp_it;
for (tmp_it = msgs_posted.begin(); tmp_it!= msgs_posted.end(); tmp_it++) {
tmp_it->toString();
}
std::cout << std::endl;
}
std::list<Message> Wall::getMsgsPosted()
{
return msgs_posted;
}
Network.h
#pragma once
class Network
{
private:
/* Singleton Implementation */
static Network* instance;
Network();
/* Misc */
std::list<User> users;
std::list<User>::iterator usr_it;
std::map<User, std::list<User*> > connections; // maybe pointer to users list?
std::map<User, std::list<User*> >::iterator map_it;
public:
/* Singleton Implementation */
Network(const Network&) = delete;
Network& operator=(const Network&) = delete;
~Network();
static Network& getInstance();
/* Other methods */
bool u_Exists(User& usr);
void addUser();
void addUser(User& usr);
void deleteUser(User& usr);
void connectUsers(User& usr1, User& usr2);
std::list<User> hasFriends(User& usr);
bool areFriends(User& usr1, User& usr2);
std::list<User> commonFriends(User* usr1, User* usr2);
};
Network.cpp
#include "pch.h"
#include <iostream>
Network::Network()
{}
...
Network& Network::getInstance()
{
static Network instance;
return instance;
}
bool Network::areFriends(User & usr1, User & usr2)
{
if (usr1 == usr2) {
return false;
}
else /*to be added*/{
return false;
}
}
The function that I am referring to is bool Network::areFriends(User & usr1, User & usr2) , used in
void Wall::postMsg(User& usr, Message msg)
{
//if are friends
if ((usr == *this->w_owner) || areFriends(usr,*this->w_owner)){
If needed I will post the rest of the classes but didn't due to size.
So shouldn't it be something like this
if ((usr == *this->w_owner) || Network::getInstance().areFriends(usr,*this->w_owner)){
In the code you've posted there's no instance of Network to call the areFriends function on.
Related
I have the following class:
class Karen
{
public:
Karen(void);
~Karen(void);
void complain(std::string level);
private:
void debug(void) const;
void info(void) const;
void warning(void) const;
void error(void) const;
};
The complain function receives a string that can contain the words debug, info, warning or error, and it has to call the appropriate function without using a forest of if/elseif/else, using instead pointers to member functions. The prototype of complain is given to me. I am new to pointers to member functions and I am not sure how to manage this. One of my attempts is this:
void Karen::complain(std::string level)
{
std::string *p = &level;
void (Karen::*f)(void) const;
(this->*(*p))();
}
The syntax of the last line is incorrect, but I am trying to do (this->*(content of pointer p))() and I don't know how to write this. Can someone help me?
Edit I am only allowed to use C++98
Syntax to call a member function via member function pointer is
(this->*memf)();
You cannot magically turn the string into a member function pointer. Sloppy speaking, names of functions do not exist at runtime. If you want such mapping you need to provide it yourself. No way around that. What you can avoid is the "forest of if-else" by using a std::unordered_map:
#include <unordered_map>
#include <string>
#include <iostream>
class Karen
{
public:
void complain(std::string level) {
static const std::unordered_map<std::string, void(Karen::*)() const> m{
{"debug",&Karen::debug},
{"info",&Karen::info},
{"warning",&Karen::warning},
{"error",&Karen::error}
};
auto it = m.find(level);
if (it == m.end()) return;
(this->*(it->second))();
}
private:
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};
int main() {
Karen k;
k.complain("info");
}
Live Demo
As mentioned in comments, you could use an enum in place of the string. When possible you should use the help of the compiler, which can diagnose a typo in an enum but not in a string. Alternatively you could directly pass a member function pointer to complain. Then implementation of complain would be trivial, no branching needed. Though this would require the methods to be public and the caller would have to deal with member function pointers.
If you are not allowed to use C++11 or newer you should have a serious talk with your teacher. Soon C++20 will be the de facto standard and things have changed quite a lot. I am not fluent in C++98 anymore, so here is just a quick fix of the above to get it working somehow. You cannot use std::unordered_map but there is std::map and initialization of the map is rather cumbersome:
#include <map>
#include <string>
#include <iostream>
class Karen
{
typedef void(Karen::*memf_t)() const;
typedef std::map<std::string,void(Karen::*)() const> map_t;
public:
void complain(std::string level) {
map_t::const_iterator it = get_map().find(level);
if (it == get_map().end()) return;
(this->*(it->second))();
}
private:
const map_t& get_map(){
static const map_t m = construct_map();
return m;
}
const map_t construct_map() {
map_t m;
m["debug"] = &Karen::debug;
m["info"] = &Karen::info;
m["warning"] = &Karen::warning;
m["error"] = &Karen::error;
return m;
}
void debug(void) const { std::cout << "debug\n"; }
void info(void) const { std::cout << "info\n"; }
void warning(void) const { std::cout << "warning\n"; }
void error(void) const { std::cout << "error\n"; }
};
int main() {
Karen k;
k.complain("info");
}
Live Demo
Let us start with the required includes.
#include <cassert>
#include <iostream>
#include <map>
Providing the log level as a string, can lead to errors, since the compiler cannot check for typos. Hence an enum::class would be a better choice for determining the log level.
enum class LogLevel {
DEBUG,
INFO,
WARNING,
ERROR
};
C++ does not offer a way to obtain a function pointer given a string. After compiling and linking the function names all have been replaced by their appropriate addresses in memory. Hence, we first need to store the function pointers, in a way that allows us to look them up as needed. For this purpose you can use a static class attribute, and store the function pointers in a std::map.
class Logger
{
public:
Logger();
~Logger();
void complain(LogLevel level);
private:
void debug() const;
void info() const;
void warning() const;
void error() const;
using HandlerMap = std::map<LogLevel, void (Logger::*)(void) const>;
static HandlerMap handlers;
};
Logger::HandlerMap Logger::handlers{
{LogLevel::DEBUG, &Logger::debug},
{LogLevel::INFO, &Logger::info},
{LogLevel::WARNING, &Logger::warning},
{LogLevel::ERROR, &Logger::error}
};
The complain method then just needs to look up the correct function pointer and call the method.
void Logger::complain(LogLevel level) {
assert(handlers.find(level) != handlers.end());
(this->*handlers[level])();
}
The remaining functions look as follows.
Logger::Logger() {}
Logger::~Logger() {}
void Logger::debug() const { std::cout << "debug" << std::endl; }
void Logger::info() const { std::cout << "info" << std::endl; }
void Logger::warning() const { std::cout << "warning" << std::endl; }
void Logger::error() const { std::cout << "error" << std::endl; }
int main(int argc, char* argv[]) {
Logger k;
k.complain(LogLevel::DEBUG);
k.complain(LogLevel::INFO);
k.complain(LogLevel::WARNING);
k.complain(LogLevel::ERROR);
}
Note, if you insist on using strings, you can replace LogLevel by std::string and LogLevel::<member> by the corresponding string.
The same can be achived using C++98. However, you will need a bit more bootstrapping.
#include <cassert>
#include <iostream>
#include <map>
enum LogLevel {
LL_DEBUG,
LL_INFO,
LL_WARNING,
LL_ERROR
};
class Logger
{
public:
Logger();
~Logger();
void complain(LogLevel level);
typedef std::map<LogLevel, void (Logger::*)() const> HandlerMap;
friend struct LoggerInit;
private:
void debug() const;
void info() const;
void warning() const;
void error() const;
static HandlerMap handlers;
};
Logger::HandlerMap Logger::handlers = Logger::HandlerMap();
struct LoggerInit {
LoggerInit() {
Logger::handlers[LL_DEBUG] = &Logger::debug;
Logger::handlers[LL_INFO] = &Logger::info;
Logger::handlers[LL_WARNING] = &Logger::warning;
Logger::handlers[LL_ERROR] = &Logger::error;
}
} logger_init;
void Logger::complain(LogLevel level) {
assert(handlers.find(level) != handlers.end());
(this->*handlers[level])();
}
Logger::Logger() {}
Logger::~Logger() {}
void Logger::debug() const { std::cout << "debug" << std::endl; }
void Logger::info() const { std::cout << "info" << std::endl; }
void Logger::warning() const { std::cout << "warning" << std::endl; }
void Logger::error() const { std::cout << "error" << std::endl; }
int main(int argc, char* argv[]) {
Logger k;
k.complain(LL_DEBUG);
k.complain(LL_INFO);
k.complain(LL_WARNING);
k.complain(LL_ERROR);
}
This is some classes of my C++ program.
ElementTerrain.h:
#ifndef ELEMENTTERRAIN_H_
#define ELEMENTTERRAIN_H_
#include <iostream>
#include <string>
using namespace std;
class ElementTerrain {
public:
virtual ~ElementTerrain(){}
virtual string getElement() const = 0;
virtual string getType() const = 0;
virtual int getStock() const = 0;
};
#endif /* ELEMENTTERRAIN_H_ */
Mine.h:
#ifndef MINE_H_
#define MINE_H_
#include "ElementTerrain.h"
using namespace std;
class Mine : public ElementTerrain{
public:
Mine();
Mine(bool, bool, int);
Mine(const Mine &);
virtual ~Mine();
string getElement(){
return "Mine";
}
string getType(){
if(this->ur == true){
return "UR";}
if(this->plu == true){
return "PLU";}
return "None";
}
int getStock() {
return stock;
}
void setStock(int stock) {
this->stock = stock;
}
bool isUr() {
return ur;
}
bool isPlu() {
return plu;
}
private :
bool ur;
bool plu;
int stock;
};
#endif /* MINE_H_ */
Mine.cpp:
#include "Mine.h"
using namespace std;
Mine::Mine() {
this->ur = false;
this->plu = false;
this->stock = 0;
}
Mine::Mine(bool ur, bool plu, int stock){
this->ur=ur;
this->plu=plu;
this->stock = stock;
}
Mine::Mine(const Mine &m){
this->ur=m.ur;
this->plu=m.plu;
this->stock = m.stock;
}
Mine::~Mine() {
// TODO Auto-generated destructor stub
}
And this is the file where I'm having errors:
#include "ElementRobot.h"
#include "Mine.h"
#include <iostream>
using namespace std;
bool ElementRobot::RecolteMine(Terrain& t, ElementRobot& r) {
if(t.plateau[x][y]->getElem() != NULL){
if(t.plateau[x][y]->getElem()->getElement() == "Mine"){
Mine *m = new Mine();
if(m.getType() == r.getType() && m.getStock()>0 && r.stock<r.cap){
m.setStock(m.getStock()-1);
t.plateau[x][y]->setElem((Mine) t.plateau[x][y]->getElem());
return true;
}
if(m.getType() == r.getType() && m.getStock()==0){
cout << "Les stocks de cette mine sont épuisés.\n" << endl;
}
if(r.stock==r.cap){
cout << "Votre robot ne peut pas porter plus de minerai.\n" << endl;
}
if(m.getType() != r.getType()){
cout << "Ce robot n'est pas adapté à cette mine.\n" << endl;
}
}}
return false;
}
I want to create an object of type Mine with the copy constructor (here I tried just with the default constructor) but it say that I cannot allocate an object of abstract type Mine, even though in my class Mine there is no pure virtual method. I'm beginner with C++ and I don't understand my mistake. I couldn't find anything on the Internet either.
The signatures of the Mine's member functions do not match those of the base class (missing const qualifiers). Therefore, you have not overridden, but overloaded them and Mine continues to be abstract and not instantiable.
It's practically like having this:
class Mine {
public:
// this has to be implemented by deriving classes
virtual string getElement() const = 0;
// this is a separate overload
string getElement() { ... };
};
Solution: Fix the signatures:
string getElement() const { ... }
// ^^^^^
and so on...
C++11's override keyword would help you greatly - it would point out that there's no non-const qualified virtual member function named getElement to override.
You forgot const in function declarations.
Look here:
class ElementTerrain {
public:
virtual ~ElementTerrain(){}
virtual string getElement() const = 0; // <- notice 'const'
virtual string getType() const = 0; // <- notice 'const'
virtual int getStock() const = 0; // <- notice 'const'
};
So add const keyword to getElement,getType and getStock functions.
class Mine : public ElementTerrain{
public:
Mine();
Mine(bool, bool, int);
Mine(const Mine &);
virtual ~Mine();
string getElement() const{ // notice 'const' is added here..
return "Mine";
}
string getType() const{ // notice 'const' is added here..
if(this->ur == true){
return "UR";}
if(this->plu == true){
return "PLU";}
return "None";
}
int getStock() const{ // notice 'const' is added here..
return stock;
}
void setStock(int stock) {
this->stock = stock;
}
bool isUr() {
return ur;
}
bool isPlu() {
return plu;
}
private :
bool ur;
bool plu;
int stock;
};
Also if you want to get rid if this error forever I advice you to add override C++11 keyword after function declaration if you want to override functions like this:
int getStock() const override{
return stock;
}
In this case your C++ compiler will check if such a virtual function exists in any superclass and will raise a compilation error if it doesn't exist.
hello eyeryone,
my protobuf version is 2.5.0, the generated header file just contains a SerializeWithCachedSizes method, I want to serialize my protobuf object to char array, and post the array by socket. in lots of tutorials refer to a method SerializeToArray method, I just need this method, but why my header file doesn't contains this method?
the first time to use protobuf, not familiar with that. if anyone can solve the problem, please show me the detail code.
proto file as:
package ddz.proto;
option optimize_for = LITE_RUNTIME;
option java_package = "ddz.proto";
option java_outer_classname = "Login";
message LoginMessage {
optional string userAccount = 1;
}
and generated header file as:
// Generated by the protocol buffer compiler. DO NOT EDIT!
// source: hello.proto
#ifndef PROTOBUF_hello_2eproto__INCLUDED
#define PROTOBUF_hello_2eproto__INCLUDED
#include <string>
#include <google/protobuf/stubs/common.h>
#if GOOGLE_PROTOBUF_VERSION < 2005000
#error This file was generated by a newer version of protoc which is
#error incompatible with your Protocol Buffer headers. Please update
#error your headers.
#endif
#if 2005000 < GOOGLE_PROTOBUF_MIN_PROTOC_VERSION
#error This file was generated by an older version of protoc which is
#error incompatible with your Protocol Buffer headers. Please
#error regenerate this file with a newer version of protoc.
#endif
#include <google/protobuf/generated_message_util.h>
#include <google/protobuf/message_lite.h>
#include <google/protobuf/repeated_field.h>
#include <google/protobuf/extension_set.h>
// ##protoc_insertion_point(includes)
namespace ddz {
namespace proto {
// Internal implementation detail -- do not call these.
void protobuf_AddDesc_hello_2eproto();
void protobuf_AssignDesc_hello_2eproto();
void protobuf_ShutdownFile_hello_2eproto();
class LoginMessage;
// ===================================================================
class LoginMessage : public ::google::protobuf::MessageLite {
public:
LoginMessage();
virtual ~LoginMessage();
LoginMessage(const LoginMessage& from);
inline LoginMessage& operator=(const LoginMessage& from) {
CopyFrom(from);
return *this;
}
static const LoginMessage& default_instance();
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
// Returns the internal default instance pointer. This function can
// return NULL thus should not be used by the user. This is intended
// for Protobuf internal code. Please use default_instance() declared
// above instead.
static inline const LoginMessage* internal_default_instance() {
return default_instance_;
}
#endif
void Swap(LoginMessage* other);
// implements Message ----------------------------------------------
LoginMessage* New() const;
void CheckTypeAndMergeFrom(const ::google::protobuf::MessageLite& from);
void CopyFrom(const LoginMessage& from);
void MergeFrom(const LoginMessage& from);
void Clear();
bool IsInitialized() const;
int ByteSize() const;
bool MergePartialFromCodedStream(
::google::protobuf::io::CodedInputStream* input);
void SerializeWithCachedSizes(
::google::protobuf::io::CodedOutputStream* output) const;
int GetCachedSize() const { return _cached_size_; }
private:
void SharedCtor();
void SharedDtor();
void SetCachedSize(int size) const;
public:
::std::string GetTypeName() const;
// nested types ----------------------------------------------------
// accessors -------------------------------------------------------
// optional string userAccount = 1;
inline bool has_useraccount() const;
inline void clear_useraccount();
static const int kUserAccountFieldNumber = 1;
inline const ::std::string& useraccount() const;
inline void set_useraccount(const ::std::string& value);
inline void set_useraccount(const char* value);
inline void set_useraccount(const char* value, size_t size);
inline ::std::string* mutable_useraccount();
inline ::std::string* release_useraccount();
inline void set_allocated_useraccount(::std::string* useraccount);
// ##protoc_insertion_point(class_scope:ddz.proto.LoginMessage)
private:
inline void set_has_useraccount();
inline void clear_has_useraccount();
::std::string* useraccount_;
mutable int _cached_size_;
::google::protobuf::uint32 _has_bits_[(1 + 31) / 32];
#ifdef GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER
friend void protobuf_AddDesc_hello_2eproto_impl();
#else
friend void protobuf_AddDesc_hello_2eproto();
#endif
friend void protobuf_AssignDesc_hello_2eproto();
friend void protobuf_ShutdownFile_hello_2eproto();
void InitAsDefaultInstance();
static LoginMessage* default_instance_;
};
// ===================================================================
// ===================================================================
// LoginMessage
// optional string userAccount = 1;
inline bool LoginMessage::has_useraccount() const {
return (_has_bits_[0] & 0x00000001u) != 0;
}
inline void LoginMessage::set_has_useraccount() {
_has_bits_[0] |= 0x00000001u;
}
inline void LoginMessage::clear_has_useraccount() {
_has_bits_[0] &= ~0x00000001u;
}
inline void LoginMessage::clear_useraccount() {
if (useraccount_ != &::google::protobuf::internal::kEmptyString) {
useraccount_->clear();
}
clear_has_useraccount();
}
inline const ::std::string& LoginMessage::useraccount() const {
return *useraccount_;
}
inline void LoginMessage::set_useraccount(const ::std::string& value) {
set_has_useraccount();
if (useraccount_ == &::google::protobuf::internal::kEmptyString) {
useraccount_ = new ::std::string;
}
useraccount_->assign(value);
}
inline void LoginMessage::set_useraccount(const char* value) {
set_has_useraccount();
if (useraccount_ == &::google::protobuf::internal::kEmptyString) {
useraccount_ = new ::std::string;
}
useraccount_->assign(value);
}
inline void LoginMessage::set_useraccount(const char* value, size_t size) {
set_has_useraccount();
if (useraccount_ == &::google::protobuf::internal::kEmptyString) {
useraccount_ = new ::std::string;
}
useraccount_->assign(reinterpret_cast<const char*>(value), size);
}
inline ::std::string* LoginMessage::mutable_useraccount() {
set_has_useraccount();
if (useraccount_ == &::google::protobuf::internal::kEmptyString) {
useraccount_ = new ::std::string;
}
return useraccount_;
}
inline ::std::string* LoginMessage::release_useraccount() {
clear_has_useraccount();
if (useraccount_ == &::google::protobuf::internal::kEmptyString) {
return NULL;
} else {
::std::string* temp = useraccount_;
useraccount_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
return temp;
}
}
inline void LoginMessage::set_allocated_useraccount(::std::string* useraccount) {
if (useraccount_ != &::google::protobuf::internal::kEmptyString) {
delete useraccount_;
}
if (useraccount) {
set_has_useraccount();
useraccount_ = useraccount;
} else {
clear_has_useraccount();
useraccount_ = const_cast< ::std::string*>(&::google::protobuf::internal::kEmptyString);
}
}
// ##protoc_insertion_point(namespace_scope)
} // namespace proto
} // namespace ddz
// ##protoc_insertion_point(global_scope)
#endif // PROTOBUF_hello_2eproto__INCLUDED
The method, SerializeToArray is defined as "bool SerializeToArray(void* data, int size) const;" within the message_lite.h file.
I can see that #include has been defined in your 'hello.proto' file. So you should have access to this function within your calling program.
See the example at proto file and call to Serialize method at https://stackoverflow.com/a/23945901/3685825
In past, I have pushed the serialized data across the socket. You may need to consider adding message Length before the actual message and send it across socket.
See the example at https://stackoverflow.com/a/11339251/3685825
Hope this helps!
I'm trying to access one of my pointers within my class, however I can't seem to even get VS to acknowledge the pointer is there.
private:
ForwardTo* forward;
and here's how I grab it from the class
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
The ForwardTo type is an inherited class that typically reads:
class ForwardToTwo : public ForwardTo
{
public:
ForwardToTwo(unsigned int strategy);
virtual std::vector<std::string> forwardMessage(Persons& person, Message& message);
unsigned int getStrategy() const { return strategy;};
private:
unsigned int strategy;
};
and finally, here's how I'm trying to access the pointer
listOfPersons.at(i).getForwardTo()->forwardMessage(listOfPersons.at(i), tempMessage);
This style of access worked previously for my OTHER pointer in my class that acts exactly this same as this one.
While typing the line to access the pointer out in VS, intelliSense picks up all the functions up to getForwardTo(), and after that, the dot operator/arrow operator don't bring up any access to functions.
Thanks again for all help.
(edit, I'm aware the function fordwardMessage() function will return a vector, I was just typing in the VS until intelliSense failed to detect the accessible functions)
(edit 2, I've tried both the . operator and the -> operator, yet neither allow intelliSense to detect any functions.)
(edit 3, additional code:
Here is my Persons Class Header:
#ifndef PERSONS_HPP
#define PERSONS_HPP
#include <string>
#include <vector>
#include <list>
#include <map>
#include "Message.hpp"
#include "TypeOne.hpp"
#include "TypeTwo.hpp"
#include "TypeThree.hpp"
#include "TypeFour.hpp"
#include "TypeFive.hpp"
class ForwardTo;
class ForwardToOne;
class ForwardToTwo;
class ForwardToThree;
class Persons
{
public:
Persons();
~Persons();
void setEmailAddress(std::string email);
std::string getEmailAddress() const;
const std::vector<std::string>& getContactList() const;
void addMessageSeen(Message message);
void addMessageContent(MessageContent mc);
void addInboxMessage(Message message);
void addContact(std::string contact);
void viewContact(const std::vector<std::string>& contacts);
void bumpContact();
void setMessageTypeOne();
void setMessageTypeTwo(unsigned int type);
void setMessageTypeThree(unsigned int quality);
void setMessageTypeFour(unsigned int type, unsigned int quality);
void setMessageTypeFive();
void setForwardTypeOne(unsigned int strategy);
void setForwardTypeTwo(unsigned int strategy);
void setForwardTypeThree(unsigned int strategy);
void printPersonsObj();
std::list<Message> getInbox() const;
MessageType& getForwardWhen() const;
ForwardTo& getForwardTo() const;
private:
std::map<MessageContent, unsigned int> messageList;
std::list<Message> inbox;
std::vector<std::string> contactList;
std::string emailAddress;
ForwardTo* forward;
MessageType* forwardWhen;
};
And here is my Persons.cpp file is:
#include "Persons.hpp"
#include "ForwardToOne.hpp"
#include "ForwardToTwo.hpp"
#include "ForwardToThree.hpp"
#include <iostream>
Persons::Persons()
:emailAddress(""), contactList(), inbox(), messageList()
{
}
Persons::~Persons()
{
//delete forwardWhen;
//delete forwardTo;
}
void Persons::addMessageContent(MessageContent mc)
{
//messageSeen.insert(mc);
}
void Persons::setEmailAddress(std::string email)
{
emailAddress = email;
}
std::string Persons::getEmailAddress() const
{
return emailAddress;
}
void Persons::addContact(std::string contact)
{
contactList.push_back(contact);
}
void Persons::addInboxMessage(Message message)
{
inbox.push_back(message);
}
void Persons::viewContact(const std::vector<std::string>& contacts)
{
for(auto i = contacts.begin(); i != contacts.end(); i ++)
{
std::cout << *i << std::endl;;
}
}
void Persons::setMessageTypeOne()
{
MessageType* forwardWhen = new TypeOne();
}
void Persons::setMessageTypeTwo(unsigned int type)
{
MessageType* forwardWhen = new TypeTwo(type);
}
void Persons::setMessageTypeThree(unsigned int quality)
{
MessageType* forwardWhen = new TypeThree(quality);
}
void Persons::setMessageTypeFour(unsigned int type, unsigned int quality)
{
MessageType* forwardWhen = new TypeFour(type, quality);
}
void Persons::setMessageTypeFive()
{
MessageType* forwardWhen = new TypeFive();
}
void Persons::setForwardTypeOne(unsigned int strategy)
{
ForwardTo* forward = new ForwardToOne(strategy);
}
void Persons::setForwardTypeTwo(unsigned int strategy)
{
ForwardTo* forward = new ForwardToTwo(strategy);
}
void Persons::setForwardTypeThree(unsigned int strategy)
{
ForwardTo* forward = new ForwardToThree(strategy);
}
const std::vector<std::string>& Persons::getContactList() const
{
return contactList;
}
void Persons::bumpContact()
{
std::vector<std::string> tempList = getContactList();
std::string tempContact = tempList.at(0);
for(unsigned int i = 0; i <= tempList.size(); i ++)
{
if(i == tempList.size())
tempList.at(--i) = tempContact;
else
tempList.at(--i) = tempList.at(i);
}
}
void Persons::addMessageSeen(Message message)
{
messageList[*message.getMessageContent()] = message.getMessageContent()->getUniqueID();
}
void Persons::printPersonsObj()
{
std::cout << "PERSONS OBJECT!" << std::endl;
std::cout << "E-mail Address: " << emailAddress << std::endl;
std::cout << std::endl;
}
std::list<Message> Persons::getInbox() const
{
return inbox;
}
MessageType& Persons::getForwardWhen() const
{
return *forwardWhen;
}
ForwardTo& Persons::getForwardTo() const
{
return *forward;
}
Incomplete type normally means that at the point at which you are trying to use getForwardTo, you have not fully declared the ForwardTo class. Indeed in your persons.hop there is only a forward declaration.
Make sure you have included the header that fully declares ForwardTo in the file containing the call site.
getForwardTo() returns a T&, just use the . to access forwardMessage()
i'm looking for a C++ replacement of the Python PubSub Library in which i don't have to connect a signal with a slot or so, but instead can register for a special Kind of messages, without knowing the object which can send it.
Perhaps you misunderstand what signals and slots are. With signals and slots you don't have to know who sends signals. Your "client" class just declares slots, and an outside manager can connect signals to them.
I recommend you to check out Qt. It's an amazing cross-platform library with much more than just GUI support. It has a convenient and efficient implementation of signals and slots which you can use.
These days it's also licensed with LGPL (in addition to GPL and commercial), so you can use it for practically any purpose.
Re your clarification comment, why not raise an exception for the error? The parent can notify the GUI, or alternatively the GUI can register for a signal the parent emits. This way the parent also doesn't have to know about the GUI.
Can you use the boost libraries? If so then combining the function and bind libraries allows you to do the following. You may be able to do the same using the tr1 functionality if your compiler supports it.
#include <iostream>
#include <list>
#include <boost/function.hpp>
#include <boost/bind.hpp>
typedef boost::function< void() > EVENT_T ;
template<typename F>
class Subject
{
public:
virtual void attach ( F o )
{
obs_.push_back ( o );
}
virtual void notify()
{
for ( typename std::list<F>::iterator i = obs_.begin(); i != obs_.end(); ++i )
( *i ) ();
}
private:
std::list<F> obs_;
} ;
class Button : public Subject<EVENT_T>
{
public:
void onClick()
{
notify() ;
};
};
class Player
{
public:
void play()
{
std::cout << "play" << std::endl ;
}
void stop()
{
std::cout << "stop" << std::endl ;
}
};
class Display
{
public:
void started()
{
std::cout << "Started playing" << std::endl ;
}
};
Button playButton ;
Button stopButton ;
Player thePlayer;
Display theDisplay ;
int main ( int argc, char **argv )
{
playButton.attach ( boost::bind ( &Player::play, &thePlayer ) );
playButton.attach ( boost::bind ( &Display::started, &theDisplay ) );
stopButton.attach ( boost::bind ( &Player::stop, &thePlayer ) );
playButton.onClick() ;
stopButton.onClick() ;
return 0;
}
So when you run this you get:
play
Started playing
stop
Press any key to continue.
So.. is this the kind of thing you are looking for?
See here and here for the source of most of this code.
EDIT: The boost::signal library might also do what you want.
Why don't you just implement one? It's not a complicated pattern (well, depending what you really want). Anyway, I already implemented a quick and dirty one some time ago. It is not optimized, synchronous and single threaded. I hope you can use it to make your own.
#include <vector>
#include <iostream>
#include <algorithm>
template<typename MESSAGE> class Topic;
class Subscriber;
class TopicBase
{
friend class Subscriber;
private:
virtual void RemoveSubscriber(Subscriber* subscriber)=0;
};
template<typename MESSAGE>
class Topic : public TopicBase
{
friend class Subscriber;
private:
class Callable
{
public:
Callable(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
:m_subscriber(subscriber)
,m_method(method)
{
}
void operator()(const MESSAGE& message)
{
(m_subscriber->*m_method)(message);
}
bool operator==(const Callable& other) const
{
return m_subscriber == other.m_subscriber && m_method == other.m_method;
}
public:
Subscriber* m_subscriber;
void (Subscriber::*m_method)(const MESSAGE&);
};
public:
~Topic()
{
//unregister each subscriber
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
std::vector<TopicBase*>& topics = i->m_subscriber->m_topics;
for(std::vector<TopicBase*>::iterator ti = topics.begin();;)
{
ti = std::find(ti, topics.end(), this);
if(ti == topics.end()) break;
ti = topics.erase(ti);
}
}
}
void SendMessage(const MESSAGE& message)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin(); i != m_subscribers.end(); i++)
{
(*i)(message);
}
}
private:
void Subscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
m_subscribers.push_back(Callable(subscriber, method));
subscriber->m_topics.push_back(this);
}
void Unsubscribe(Subscriber* subscriber, void (Subscriber::*method)(const MESSAGE&))
{
std::vector<Callable>::iterator i = std::find(m_subscribers.begin(), m_subscribers.end(), Callable(subscriber, method));
if(i != m_subscribers.end())
{
m_subscribers.erase(i);
subscriber->m_topics.erase(std::find(subscriber->m_topics.begin(), subscriber->m_topics.end(), this)); //should always find one
}
}
virtual void RemoveSubscriber(Subscriber* subscriber)
{
for(std::vector<Callable>::iterator i = m_subscribers.begin() ; i != m_subscribers.end(); i++)
{
if(i->m_subscriber == subscriber)
{
m_subscribers.erase(i);
break;
}
}
}
private:
std::vector<Callable> m_subscribers;
};
class Subscriber
{
template<typename T> friend class Topic;
public:
~Subscriber()
{
for(std::vector<TopicBase*>::iterator i = m_topics.begin(); i !=m_topics.end(); i++)
{
(*i)->RemoveSubscriber(this);
}
}
protected:
template<typename MESSAGE, typename SUBSCRIBER>
void Subscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Subscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
template<typename MESSAGE, typename SUBSCRIBER>
void Unsubscribe(Topic<MESSAGE>& topic, void (SUBSCRIBER::*method)(const MESSAGE&))
{
topic.Unsubscribe(this, static_cast<void (Subscriber::*)(const MESSAGE&)>(method));
}
private:
std::vector<TopicBase*> m_topics;
};
// Test
Topic<int> Topic1;
class TestSubscriber1 : public Subscriber
{
public:
TestSubscriber1()
{
Subscribe(Topic1, &TestSubscriber1::onTopic1);
}
private:
void onTopic1(const int& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
class TestSubscriber2 : public Subscriber
{
public:
void Subscribe(Topic<const char*> &subscriber)
{
Subscriber::Subscribe(subscriber, &TestSubscriber2::onTopic);
}
void Unsubscribe(Topic<const char*> &subscriber)
{
Subscriber::Unsubscribe(subscriber, &TestSubscriber2::onTopic);
}
private:
void onTopic(const char* const& message)
{
std::cout<<"TestSubscriber1::onTopic1 "<<message<<std::endl;
}
};
int main()
{
Topic<const char*>* topic2 = new Topic<const char*>();
{
TestSubscriber1 testSubscriber1;
Topic1.SendMessage(42);
Topic1.SendMessage(5);
}
Topic1.SendMessage(256);
TestSubscriber2 testSubscriber2;
testSubscriber2.Subscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Unsubscribe(*topic2);
topic2->SendMessage("owl");
testSubscriber2.Subscribe(*topic2);
delete topic2;
return 0;
}