Can someone fix my code? Here is the error I get: $ g++ main.cpp User.cpp Messag
ID: 3862579 • Letter: C
Question
Can someone fix my code?
Here is the error I get:
$ g++ main.cpp User.cpp Message.cpp Topic.cpp Reply.cpp BBoard.cpp -Wall -o a.out
BBoard.cpp: In member function ‘bool BBoard::load_messages(const string&)’:
BBoard.cpp:86:66: error: cannot allocate an object of abstract type ‘Topic’
Message *mg = new Topic( author, subject, body, id);
^
In file included from BBoard.cpp:3:0:
Topic.h:4:7: note: because the following virtual functions are pure within ‘Topic’:
class Topic: public Message{
^
In file included from BBoard.h:6:0,
from BBoard.cpp:1:
Message.h:41:19: note: virtual bool Message::isReply() const
virtual bool isReply() const = 0;
^
Message.h:43:21: note: virtual std::string Message::toFormattedString() const
virtual string toFormattedString() const = 0; // New!!
^
BBoard.cpp:93:67: error: cannot allocate an object of abstract type ‘Reply’
Message *mg = new Reply( author, subject, body, id);
^
In file included from BBoard.cpp:2:0:
Reply.h:4:7: note: because the following virtual functions are pure within ‘Reply’:
class Reply:public Message{
^
In file included from BBoard.h:6:0,
from BBoard.cpp:1:
Message.h:41:19: note: virtual bool Message::isReply() const
virtual bool isReply() const = 0;
^
Message.h:43:21: note: virtual std::string Message::toFormattedString() const
virtual string toFormattedString() const = 0; // New!!
^
BBoard.cpp: In member function ‘void BBoard::add_reply()’:
BBoard.cpp:179:77: error: cannot allocate an object of abstract type ‘Reply’
Message *mg = new Reply( current_user->get_username(), subject, body, id );
^
In file included from BBoard.cpp:2:0:
Reply.h:4:7: note: since type ‘Reply’ has pure virtual functions
class Reply:public Message{
^
BBoard.cpp: In member function ‘void BBoard::add_topic()’:
BBoard.cpp:198:77: error: cannot allocate an object of abstract type ‘Topic’
Message *mg = new Topic( current_user->get_username(), subject, body, id );
^
In file included from BBoard.cpp:3:0:
Topic.h:4:7: note: since type ‘Topic’ has pure virtual functions
class Topic: public Message{
Here is my code:
main.cpp
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
using namespace std;
#include "BBoard.h"
#include "User.h"
#include "Message.h"
#include "Reply.h"
#include "Topic.h"
/*int main(int argc, char* argv[])
{
string file = argv[argc - 1];
// Message m;
// m.display();
// cout << endl;
// Message m1("Zafir", "Great Subject", "THis is the body!!");
// m1.display();
BBoard board;
board.setup(file);
board.login();
return 0;
}*/
int main(int argc, char **argv)
{
// check commandline arguments
// if (argc != 3){
// cout << "ERROR: Invalid program call." << endl
// << "Usage: <program_name> userfile datafile" << endl;
//return 1;
//}
string userfile("users1.txt");
string datafile("data.txt");
BBoard bb("Bulletin Board");
// load users from file
if (!bb.load_users(userfile))
{
cout << "ERROR: Cannot load users from " << userfile << endl;
return 1;
}
// load messages
if (!bb.load_messages(datafile))
{
cout << "ERROR: Cannot load messages from " << datafile << endl;
return 1;
}
bb.login();
//bool a = bb.save_messages("out.txt");
//a=a;
bb.run();
// save messages
if (!bb.save_messages(datafile))
{
cout << "ERROR: Cannot save messages to " << datafile << endl;
return 1;
}
// cout << "saved" << endl;
return 0;
}
User.h
#ifndef _USER_H
#define _USER_H
#include <string>
using namespace std;
class User
{
private:
string username;
string password;
public:
//creates a user with empty name and password.
User();
// creates a user with given username and password.
User(const string& uname, const string& pass);
//returns the username
string get_username() const;
bool check(const string &uname, const string &pass) const;
// sets a new password. This function will not be used in the
// current assignment.
//void set_password(const string &newpass);
};
#endif
User.cpp
#include "User.h"
#include <string>
using namespace std;
User::User(){
username="";
password="";
}
// creates a user with given username and password.
User::User(const string& uname, const string& pass){
username=uname;
password=pass;
}
//returns the username
string User::get_username() const{
return username;
}
bool User::check(const string &uname, const string &pass) const{
if(uname.empty()||pass.empty())
return false;
return username==uname && password==pass;
}
Message.h
#ifndef MESSAGE_H
#define MESSAGE_H
#include <iostream>
#include <vector>
using namespace std;
//inclusion guards
//includes
class Message { // abstract base class
// protected will allow access to these members by objects of derived classes
protected:
string author;
string subject;
string body;
unsigned id; // New !!
// This will be the size of the messageList vector to which the
// newly constructed Message * is being pushed_back
vector<Message *> childList; // New !!
// This is how a Message is able to keep track of its Replies
public:
// default constructor
Message();
// Parameterized constructor;
// id will be the size of current BBoard's messageList
Message(const string &athr,
const string &sbjct,
const string &body,
unsigned id);
// Be very careful here: some Messages will have two pointers to
// them, stored in very different places!
// Where are they, and who should be responsible for deleting
// them?
virtual ~Message();
// returns true if the object is a Reply.
virtual bool isReply() const = 0;
virtual string toFormattedString() const = 0; // New!!
/* This function is responsible for printing the Message
* (whether Topic or Reply), and and all of the Message's
* "subtree" recursively:
* After printing the Message with indentation n and appropriate
* format (see output details), it will invoke itself
* recursively on all of the Replies in its childList,
* incrementing the indentation value at each new level.
*
* Note: Each indentation increment represents 2 spaces. e.g. if
* indentation == 1, the reply should be indented 2 spaces, if
* it's 2, indent by 4 spaces, etc.
*/
void print(unsigned indentation) const; // New !!
//returns the subject string.
const string & getSubject() const;
// returns the ID.
unsigned getID() const; // New !!
// Adds a pointer to the child to the parent's childList.
void addChild(Message *child); // New !!
};
//end inc guards
#endif
Message.cpp
#include "Message.h"
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
Message::Message(){
}
Message::Message(const string &athr,const string &sbjct,const string &b, unsigned i){
author = athr;
subject = sbjct;
body = b;
id = i;
}
void Message::print(unsigned indentation) const{
if( indentation !=0 )
cout << endl;
for( unsigned i = 0; i < indentation ; ++i )
cout << " ";
cout << "Message #" << id << ": " << subject << endl;
for( unsigned i = 0; i < indentation ; ++i )
cout << " ";
string newbody(body);
unsigned pos = newbody.find_first_of( ' ', 0 );
while( pos < newbody.size() ){
newbody.insert( pos + 1 , (int)indentation * 2, ' ' ); //insert before position pos + 1
pos = newbody.find_first_of( ' ', pos + 1 );
}
cout << "from " << author << ": " << newbody << endl;
//cout << childList.size() << endl;
++indentation;
for( unsigned i = 0; i < childList.size(); ++i )
childList[ i ]->print( indentation );
}
const string & Message::getSubject() const{
return subject;
}
unsigned Message::getID() const{
return id;
}
void Message::addChild(Message *child){
childList.push_back( child );
}
Message::~Message(){
for( unsigned i = 0; i < childList.size(); ++i )
childList[ i ] = NULL;
}
Topic.h
#ifndef TOPIC_H
#define TOPIC_H
#include "Message.h"
class Topic: public Message{
public:
Topic();
Topic(const string &athr,
const string &sbjct,
const string &bdy,
unsigned id);
virtual bool is_reply() const;
string to_formatted_string() const;
};
#endif
Topic.cpp
#include "Topic.h"
#include <sstream>
Topic::Topic(){
}
Topic::Topic(const string &athr,
const string &sbjct,
const string &bdy,
unsigned i){
author = athr;
subject = sbjct;
body = bdy;
id = i;
}
bool Topic::is_reply() const{
return false;
}
string Topic::to_formatted_string() const{
string s("<begin_topic>");
s +=' ';
stringstream ss;
ss << id;
s += ":id: " + ss.str()+ ' ';
s += ":subject: " + subject + ' ';
s += ":from: " + author + ' ';
if( !childList.empty() ){
s += ":children:";
for( unsigned i = 0; i < childList.size(); ++i ){
stringstream ssid;
ssid << childList[ i ]->getID();
s += ' ' + ssid.str();
}
s += ' ';
}
s += ":body: " + body + ' ';
s += "<end>";
return s;
}
Reply.h
#ifndef REPLY_H
#define REPLY_H
#include "Message.h"
class Reply:public Message{
public:
//default constructor
Reply();
Reply(const string &athr,
const string &sbjct,
const string &body,
unsigned id);
bool is_reply() const;
string to_formatted_string() const;
};
#endif
Reply.cpp
#include "Reply.h"
#include <sstream>
Reply::Reply(){
}
Reply::Reply(const string &athr, const string &sbjct, const string &bdy, unsigned i){
author = athr;
subject = sbjct;
body = bdy;
id = i;
}
bool Reply::is_reply() const{
return true;
}
string Reply::to_formatted_string() const{
string s("<begin_reply>");
s +=' ';
stringstream ss;
ss << id;
s += ":id: " + ss.str()+ ' ';
s += ":subject: " + subject + ' ';
s += ":from: " + author + ' ';
if( !childList.empty() ){
s += ":children:";
for( unsigned i = 0; i < childList.size(); ++i ){
stringstream ssid;
ssid << childList[ i ]->getID();
s += ' ' + ssid.str();
}
s += ' ';
}
s += ":body: " + body + ' ';
s += "<end>";
return s;
}
BBoard.h
#ifndef _BBOARD_H
#define _BBOARD_H
#include <string>
#include <vector>
#include "User.h"
#include "Message.h"
using namespace std;
class BBoard{
private:
string title;
vector<User> user_list;
const User *current_user;
vector<Message*> message_list;
const User * get_user(const string &name, const string &pw) const;
void display() const;
void add_topic();
void add_reply();
public:
BBoard();
BBoard(const string& ttl);
bool load_users(const string& userfile);
bool load_messages(const string& datafile);
bool save_messages(const string& datafile);
void login();
void run();
~BBoard( );
};
#endif
BBoard.cpp
#include "BBoard.h"
#include "Reply.h"
#include "Topic.h"
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
using namespace std;
BBoard::BBoard(){
current_user=NULL;
}
BBoard::BBoard(const string &ttl){
title=ttl;
current_user = NULL;
}
bool BBoard::load_users(const string &userfile){
ifstream fIn( userfile.c_str() );
if( fIn.is_open() ) {
string temp1,temp2;
fIn>>temp1;
while(temp1!="end"){
fIn>>temp2;
user_list.push_back(User(temp1,temp2));
fIn>>temp1;
}
fIn.close();
return true;
}
else
return false;
}
bool BBoard::load_messages(const string& datafile){
ifstream fIn( datafile.c_str() );
if( fIn.is_open() ) {
string tmp, strBegin;
string author, subject;
unsigned id = 0;
vector< string > children;
getline( fIn, tmp ); //pass over the first line , number of messages
while( fIn.good() ){
getline( fIn, strBegin );
if( strBegin[ strBegin.size() -1 ] == ' ' )
strBegin.erase( strBegin.size() -1 );
getline( fIn, tmp ); //pass over the line with id information
getline( fIn, subject);
if( subject[ subject.size() -1 ] == ' ' )
subject.erase( subject.size() -1 );
subject.erase( 0, 10);
getline( fIn, author);
if( author[ author.size() -1 ] == ' ' )
author.erase( author.size() -1 );
author.erase( 0, 7);
string body;
string str_children;
getline( fIn, tmp ); //tmp may be children or body
if( tmp[ tmp.size() -1 ] == ' ' )
tmp.erase( tmp.size() -1 );
if( tmp.find( "children", 0 ) != string::npos ){
tmp.erase( 0, 11);
children.push_back(tmp);
getline( fIn, tmp );
if( tmp[ tmp.size() -1 ] == ' ' )
tmp.erase( tmp.size() -1 );
}
else
children.push_back("");
while( tmp != "<end>" ) {
body = body + ' ' + tmp;
getline( fIn, tmp );
if( tmp[ tmp.size() -1 ] == ' ' )
tmp.erase( tmp.size() -1 );
}
++id;
//cout << id << endl;
body.erase( 0, body.find_first_of(":", 1)); //remove the first ' '
body.erase( 0, body.find_first_of(":", 1) + 2 ); //remove :body:
//cout << body << endl;
if ( strBegin == "<begin_topic>" ){
//cout << " strBegin :" << strBegin << endl;
//cout << " size :" << strBegin.size() << endl;
Message *mg = new Topic( author, subject, body, id);
//cout << "topic added " << endl;
message_list.push_back( mg );
}
else {
//cout << " strBegin :" << strBegin << endl;
//cout << " size :" << strBegin.size() << endl;
Message *mg = new Reply( author, subject, body, id);
//cout << "reply added " << endl;
message_list.push_back( mg );
}
}
fIn.close();
int child;
for( unsigned i = 0; i < children.size(); ++i ){
stringstream iss( children[i] );
while( iss >> child ){
message_list[ i ] -> addChild( message_list[ child - 1] );
//cout << child << " is added" << endl;
}
}
return true;
}
else
return false;
}
bool BBoard::save_messages(const string& datafile){
ofstream fOut( datafile.c_str() );
if( fOut.is_open() ) {
fOut << message_list.size();
for( unsigned i = 0; i < message_list.size(); ++i )
fOut << endl << message_list[ i ]->toFormattedString() ;
fOut.close();
return true;
}
else
return false;
}
const User * BBoard::get_user(const string &name, const string &pw) const{
for( unsigned i = 0; i < user_list.size(); ++i ){
if( user_list[i].check(name,pw) )
return &user_list[i];
}
return NULL;
}
void BBoard::login(){
string name, pass;
cout << endl << "Welcome to Jack's Amazing Bulletin Board" << endl;
while(true){
cout<<"Enter your username ("Q" or "q" to quit):";
getline(cin,name);
if(name.compare("Q")==0 || name.compare("q")==0){
cout<<"Bye!"<<endl;
return;
}
cout<<"Enter your password:";
getline(cin,pass);
current_user = get_user( name, pass );
if( current_user )
break;
cout<<"Invalid Username or Password!"<<endl<<endl;
}
}
void BBoard::add_reply(){
string subject, body, tmp;
int id;
int message_id;
while( true ){
cout << endl << "Enter Message ID (-1 for Menu): " ;
getline( cin, tmp);
stringstream ss( tmp );
ss >> message_id;
//cin >> message_id; //****** use this will make getline( cin, tmp ) doesn't work
if( message_id == -1 )
return;
if( message_id > 0 && message_id <= (int)message_list.size() )
break;
cout << "Invalid Message ID!!" << endl;
}
id = message_list.size() + 1;
subject = "Re: " + message_list[ message_id - 1 ]->getSubject();
cout << "Enter Body: ";
getline( cin, tmp);
if( tmp == "" ){
body = body + ' ';
getline( cin, tmp);
}
while ( tmp != "" ){
body = body + ' ' + tmp;
getline( cin, tmp );
}
body.erase( 0, 1 ); //remove the first character ' '
Message *mg = new Reply( current_user->get_username(), subject, body, id );
message_list.push_back( mg );
message_list[ message_id - 1 ]->addChild( mg );
}
void BBoard::add_topic(){
string subject, body, tmp;
int id;
id = message_list.size() + 1;
cout << "Enter Topic: ";
getline( cin, subject );
cout << "Enter Body: ";
getline( cin, tmp);
if( tmp == "" )
getline( cin, tmp);
while ( tmp != "" ){
body = body + ' ' + tmp;
getline( cin, tmp );
}
body.erase( 0, 1 ); //remove the first character ' '
Message *mg = new Topic( current_user->get_username(), subject, body, id );
message_list.push_back( mg );
}
//display should be rewritten
void BBoard::display() const{
if( message_list.size()==0 )
cout<<endl<<"Nothing to Display."<<endl;
else {
cout<< endl << "-------------------------------------------------------------------------------"<<endl;
for( unsigned i = 0;i < message_list.size(); ++i){
//cout << " I have been here " << endl;
if( !message_list[i]->isReply() ){
message_list[i]->print( 0 );
cout<<"-------------------------------------------------------------------------------"<<endl;
}
}
}
}
void BBoard::run(){
if( !current_user )
return;
cout<< endl << "Welcome back "<<current_user->get_username()<<"!"<<endl;
while(true){
cout<< endl << "Menu"<<endl;
cout<<" - Display Messages ('D' or 'd')"<<endl;
cout<<" - Add New Topic ('N' or 'n')"<<endl;
cout<<" - Add Reply to a Topic ('R' or 'r')"<<endl;
cout<<" - Quit ('Q' or 'q')"<<endl;
cout<<"Choose an action:";
//cin.ignore(100,' ');
//char c;
//cin>>c;
string s;
getline(cin,s);
if(s=="N" || s=="n")
add_topic();
else if(s=="R" || s=="r")
add_reply();
else if(s=="D" || s=="d")
display();
else if(s=="Q" || s=="q"){
cout<<"Bye!"<<endl;
return;
}
}
}
BBoard::~BBoard( ){
//delete current_user;
for( unsigned i = 0; i < message_list.size(); ++i ){
if( message_list[i] )
delete message_list[i];
}
}
Explanation / Answer
Issue is with the declaration and definition of virtual functions in Topic and Reply classes
If you are deriving from an abstract class, then make sure you override and define all pure virtual functions for your class.
Signature of isReply and toFormattedString functions is not correct
Topic.h
#ifndef TOPIC_H
#define TOPIC_H
#include "Message.h"
class Topic: public Message{
public:
Topic();
Topic(const string &athr,
const string &sbjct,
const string &bdy,
unsigned id);
bool isReply() const;
string toFormattedString() const;
};
#endif
Topic.cpp
#include "Topic.h"
#include <sstream>
Topic::Topic(){
}
Topic::Topic(const string &athr,
const string &sbjct,
const string &bdy,
unsigned i){
author = athr;
subject = sbjct;
body = bdy;
id = i;
}
bool Topic::isReply() const{
return false;
}
string Topic::toFormattedString() const{
string s("<begin_topic>");
s +=' ';
stringstream ss;
ss << id;
s += ":id: " + ss.str()+ ' ';
s += ":subject: " + subject + ' ';
s += ":from: " + author + ' ';
if( !childList.empty() ){
s += ":children:";
for( unsigned i = 0; i < childList.size(); ++i ){
stringstream ssid;
ssid << childList[ i ]->getID();
s += ' ' + ssid.str();
}
s += ' ';
}
s += ":body: " + body + ' ';
s += "<end>";
return s;
}
Reply.h
#ifndef REPLY_H
#define REPLY_H
#include "Message.h"
class Reply:public Message{
public:
//default constructor
Reply();
Reply(const string &athr,
const string &sbjct,
const string &body,
unsigned id);
bool isReply() const;
string toFormattedString() const;
};
#endif
Reply.cpp
#include "Reply.h"
#include <sstream>
Reply::Reply(){
}
Reply::Reply(const string &athr, const string &sbjct, const string &bdy, unsigned i){
author = athr;
subject = sbjct;
body = bdy;
id = i;
}
bool Reply::isReply() const{
return true;
}
string Reply::toFormattedString() const{
string s("<begin_reply>");
s +=' ';
stringstream ss;
ss << id;
s += ":id: " + ss.str()+ ' ';
s += ":subject: " + subject + ' ';
s += ":from: " + author + ' ';
if( !childList.empty() ){
s += ":children:";
for( unsigned i = 0; i < childList.size(); ++i ){
stringstream ssid;
ssid << childList[ i ]->getID();
s += ' ' + ssid.str();
}
s += ' ';
}
s += ":body: " + body + ' ';
s += "<end>";
return s;
}