I currently have an abstract User class and a Student class which inherits from user. I'm attempting to initialize an instance of the Student class from main. I'm receiving this error
Undefined symbols for architecture i386:
"Student::Student()", referenced from:
_main in ccJo7npg.o
"Student::~Student()", referenced from:
_main in ccJo7npg.o
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status
User Class:
#include <iostream>
#import <stdio.h>
#import <string.h>
using namespace std;
class User
{
public:
void setName(const string n)
{
name = n;
}
string getName()
{
return name;
}
void setUsername(const string u)
{
username = u;
}
string getUsername()
{
return username;
}
void setPassword(const string p)
{
password = p;
}
string getPassword()
{
return password;
}
void setID(const int ID)
{
this->ID=ID;
}
int getID()
{
return ID;
}
void setClassID(const int cid)
{
classID=cid;
}
int getClassID()
{
return classID;
}
void logOut()
{
cout<<"you have logged out"<<endl;
}
void print()
{
cout<< "Student : "<< ID << name << " "<< username << " " << password << endl;
}
virtual void menu()=0;
protected:
int classID, ID;
string name, username, password;
};
Student Class:
#include <iostream>
#include "User.h"
using namespace std;
class Student: public User
{
public:
Student()
{
classID=0;
ID=0;
username="";
name="";
password="";
}
~Student()
{
cout<<"destructor"<<endl;
}
void studyDeck(const int i)
{
}
void viewScores(const int)
{
}
void viewScores()
{
}
virtual void menu()
{
cout << "Student menu" << endl;
}
};
Main.cpp:
#include <iostream>
#include "User.h"
#include "Student.h"
using namespace std;
int main()
{
Student s;
return 0;
}
I'm compiling with g++ with " g++ User.cpp Student.cpp main.cpp "
Thanks!
GCC is not producing code for the Student constructor and destructor because they are defined inside of the class declaration. That's why those symbols are missing and generating a link error. At a minimum, you need to move the function bodies for the Student constructor and destructor outside of the class declaration and provide just the signature (no body) in the definition:
class Student: public User
{
Student();
~Student();
...
};
You would define these function bodies in Student.cpp after the class definition as follows:
Student::Student()
{
classID=0;
ID=0;
username="";
name="";
password="";
}
Student::~Student()
{
cout<<"destructor"<<endl;
}
Though it's not necessary, you should separate all of the function definitions from their implementation. To do this, you would omit the class definition from the Student.cpp file; and instead include Student.h in Student.cpp (even though you didn't post Student.h, it appears to be correct or the program would not have compiled). In other words, "Student.h" would contain "class Student { ... };" with just function signatures and no function bodies inside the braces and "Student.cpp" would contain all of the function definitions with bodies such as:
void Student::menu()
{
cout << "Student menu" << endl;
}
If you do this, you will also need #ifndef guards in the .h files as Kevin Grant explained.
You would treat User.cpp and User.h in the same way.
Related
I'm creating a cpp program using functions that are applied to C++11. Even though the code seems correct and has no syntax errors i'm getting this message when i compile:
/tmp/cce9dpew.o: In function `Object::Object()':
classes.cpp:(.text+0xd): undefined reference to `vtable for Object'
/tmp/cce9dpew.o: In function `Object::~Object()':
classes.cpp:(.text+0x45): undefined reference to `vtable for Object'
/tmp/cce9dpew.o:(.rodata._ZTI6String[_ZTI6String]+0x10): undefined reference to `typeinfo for Object'
collect2: error: ld returned 1 exit status
I have to add here that if i put all those .cpp and .h files in one it runs Aok printing constructor and destructor cout's just fine.
Can someone help?The code is below.
compile recipe i used to run them all together: g++ -std=c++0x classes.h classes.cpp mainiz.cpp
classes.h:
#ifndef CLASSES_H
#define CLASSES_H
#include <iostream>
#include <cstring>
using namespace std;
class Object
{
private:
int id;
public:
Object();
~Object();
void set_id(int ids);
int get_id();
void Equal(Object* bj) const;
void Identical(Object* bj) const;
virtual Object* clone();
virtual void toString();
};
class String:public Object
{
string characters;
public:
String();
~String();
void set_char(string a);
string get_char();
String* clone();
void toString();
int Length();
void Clear(string a);
string& Concat(string &a);
char At(char b);
string& UpdateAt(string a,string charact);
void Print(const string a) const;
};
#endif //CLASSES_H
classes.cpp:
#include <iostream>
#include <cstring>
#include "classes.h"
using namespace std;
//FOR OBJECT CLASS
Object::Object(){ cout << "An object just got created." << endl;}
Object::~Object(){ cout << "An object just got destroyed." << endl; }
void Object::set_id(int ids) { this->id = ids; }
int Object::get_id() { return this->id;}
void Object::Equal(Object* bj) const
{
if((this->id == bj->id))
{
cout << "The objects are equal." << endl;
}
else
{
cout << "The objects are not equal." <<endl;
}
}
void Object::Identical(Object* bj) const
{
if(this==bj)
{
cout << "The objects are identical." <<endl;
}
else
{
cout << "The objects are not identical." <<endl;
}
}
//FOR STRING CLASS
String::String(){ cout << "String just created" << endl;}
String::~String(){ cout << "String to be destroyed" << endl;}
void String::set_char(string a) { this->characters = a;}
string String::get_char() { return this->characters;}
String* String::clone() { return this;}
void String::toString() {cout << "characters" << endl;}
int String::Length()
{
string a = this->characters;
return a.length();
}
void String::Clear(string a)
{
this->characters.clear();
}
string& String::Concat(string &a){ return (this->characters.append(a));}
char String::At(char b) { return (this->characters.find(b)); }
string& String::UpdateAt(string a,string charact)
{
int position=this->characters.find(charact);
return this->characters.replace(position,1,a);
}
void String::Print(const string a) const { cout << "print of string:" << a << endl; }
mainiz.cpp:
#include <iostream>
#include <cstring>
#include "classes.h"
using namespace std;
int main()
{
Object k;
Object *st = new String;
String d;
}
Making the destructor for Object class "virtual" you would get another error for undefined reference to Object::clone and Object::toString.
You can try what #Igor suggested, but your current mainiz.cpp code won't work because C++ doesn't allow an instance of a class with pure virtual methods.
You can try the following code:
class Object {
virtual ~Object();
virtual Object* clone();
virtual void toString();
};
Object* Object::clone() {
// Make your implementation here
return nullptr;
}
void Object::toString() {
// Make your implementation here
}
Object::clone and Object::toString are declared but never implemented.
If you want to leave them unimplemented, make them pure virtual, as in
class Object {
virtual Object* clone() = 0;
};
None of the solutions given above were correct.The problem was within my compilation recipe.These functions started existing after C++11 so if you're using something like that your compilation recipe should be:
g++ -g -std=c++11 -o executable file.cpp main.cpp
This question already has answers here:
Why can I not push_back a unique_ptr into a vector?
(2 answers)
Closed 3 years ago.
I am trying to create one vector for two types of users. Admin and Customer who are both derived from an abstract class, BaseUser. However I tried some of the answers provided online but I can't seem to make this work. I keep getting error: use of delete function 'std::unique_ptr<....
I am still struggling with fully grasping the concept of pointers so that could be why im stuck with this problem.
#ifndef BASEUSER_H
#define BASEUSER_H
#include <string>
class BaseUser
{
private:
int id;
int idCounter = 0;
std::string fullname;
std::string username;
std::string password;
protected:
bool isAdmin;
public:
BaseUser();
BaseUser(std::string fullname, std::string username, std::string password);
virtual void setIsAdmin(bool isAdmin) = 0;
void setID(int id);
void setFullname(std::string fullname);
void setUsername(std::string username);
void setPassword(std::string password);
unsigned long int getID();
std::string getFullname();
std::string getUsername();
std::string getPassword();
};
#endif
#ifndef ADMIN_H
#define ADMIN_H
#include "BaseUser.h"
class Admin : public BaseUser
{
public:
Admin(std::string fullname,std::string username,std::string password);
void setIsAdmin(bool isAdmin);
bool getIsAdmin();
};
#endif
#ifndef USERMANAGER_H
#define USERMANAGER_H
#include "Admin.h"
#include "Customer.h"
#include <vector>
#include <memory>
class UserManager
{
private:
std::vector<std::unique_ptr<BaseUser>> users;
bool isAuthenticated;
public:
std::vector<std::unique_ptr<BaseUser>> getUsers();
bool login(std::string name, std::string password);
bool logout();
void createAdmin(Admin);
// void createCustomer(Customer);
};
#endif
Object creation method declaration inside the usermanager class:
void UserManager::createAdmin(Admin admin))
{
users.push_back( move(admin) )
}
I also tried to push using make_unique, but still the same error.
View that return the object to the createAdmin() method:
// View.cpp
Admin View::createAdminView()
{
string fullname, username, password;
cout << "~ Register Admin ~" << endl << endl;
cout << "Name: ";
cin.ignore();
getline(cin, fullname);
cout << "Username: ";
cin >> username;
cout << "Password: ";
cin >> password;
return Admin(fullname, username, password);
}
try changing createAdmin into this:
void UserManager::createAdmin(Admin admin)
{
users.push_back( std::make_unique<Admin>(admin) );
}
push_back of a vector<T> wants a const T& or (in this case) a T&&
header file:
#ifndef H_bankAccount;
#define H_bankAccount;
class bankAccount
{
public:
string getAcctOwnersName() const;
int getAcctNum() const;
double getBalance() const;
virtual void print() const;
void setAcctOwnersName(string);
void setAcctNum(int);
void setBalance(double);
virtual void deposit(double)=0;
virtual void withdraw(double)=0;
virtual void getMonthlyStatement()=0;
virtual void writeCheck() = 0;
private:
string acctOwnersName;
int acctNum;
double acctBalance;
};
#endif
cpp file:
#include "bankAccount.h"
#include <string>
#include <iostream>
using std::string;
string bankAccount::getAcctOwnersName() const
{
return acctOwnersName;
}
int bankAccount::getAcctNum() const
{
return acctNum;
}
double bankAccount::getBalance() const
{
return acctBalance;
}
void bankAccount::setAcctOwnersName(string name)
{
acctOwnersName=name;
}
void bankAccount::setAcctNum(int num)
{
acctNum=num;
}
void bankAccount::setBalance(double b)
{
acctBalance=b;
}
void bankAccount::print() const
{
std::cout << "Name on Account: " << getAcctOwnersName() << std::endl;
std::cout << "Account Id: " << getAcctNum() << std::endl;
std::cout << "Balance: " << getBalance() << std::endl;
}
Please help i get an error under getAcctOwnersName, and setAcctOwnersName stating that the declaration is incompatible with "< error-type > bankAccount::getAcctOwnersName() const".
You need to
#include <string>
in your bankAccount header file, and refer to the strings as std::string.
#ifndef H_bankAccount;
#define H_bankAccount;
#include <string>
class bankAccount
{
public:
std::string getAcctOwnersName() const;
....
once it is included in the header, you no longer need to include it in the implementation file.
I've found that when a private member variable and a member function have the same name the IDE gives me the "incompatible" error, perhaps that is what you are experiencing...
Sometimes this error occur because it's vary from machine to machine. Your program will work fine if you declare your class and all of its implementations in one file instead doing declaration of class in other file and linked it with your driver file.
Again: This is totally machine dependent error.
In visual studio 2012 you will face this kind of error because it not work for these files while in other versions of vs you will not face any error type exception.
Hope it's worth.....
main:
#include <iostream>
#include <string>
#include "serviceChargeChecking.h"
int main()
{
serviceChargeChecking newAccount("Crim", 111222, 50.00, 100, 1.00);
system("PAUSE");
return 0;
}
serviceChargeChecking.h:
#ifndef H_serviceChargeChecking
#define H_serviceChargeChecking
#include "checkingaccount.h"
#include <string>
class serviceChargeChecking: public checkingAccount
{
public:
void setMonthlyFee(double);
void writeCheck(int);
void getMonthlyStatement() const;
serviceChargeChecking(std::string =" ",int = 0, double = 0.00, int= 0, double = 0.00);
private:
double serviceCharge;
};
#endif
serviceChargeChecking.cpp:
#include "serviceChargeChecking.h"
#include <iostream>
using std::string;
void serviceChargeChecking::setMonthlyFee(double fee)
{
serviceCharge=fee;
}
void serviceChargeChecking::getMonthlyStatement() const
{
checkingAccount::getMonthlyStatement();
std::cout<< "Service Charge: " << serviceCharge << std::endl;
}
void serviceChargeChecking::writeCheck(int ammount)
{
if(checkingAccount::getChecks()>0)
{
checkingAccount::setChecks(checkingAccount::getChecks()-ammount);
}
else
{
std::cout<<"No checks available." << std::endl;
}
}
serviceChargeChecking::serviceChargeChecking(string name, int acct, double bal, int numCheck, double sCharge)
{
bankAccount::setAcctOwnersName(name);
bankAccount::setAcctNum(acct);
bankAccount::setBalance(bal);
checkingAccount::setChecks(numCheck);
serviceCharge=sCharge;
}
checkingAccount.h:
#ifndef H_checkingAccount
#define H_checkingAccount
#include "bankAccount.h"
#include <iostream>
class checkingAccount: public bankAccount
{
public:
virtual void writeCheck()=0;
void deposit(double);
void withdraw(double);
void getMonthlyStatement() const;
int getChecks();
void setChecks(int);
private:
int numChecks;
};
#endif
checkingAccount.cpp:
#include "checkingAccount.h"
#include <iostream>
int checkingAccount::getChecks()
{
return numChecks;
}
void checkingAccount::setChecks(int c)
{
numChecks=c;
}
void checkingAccount::deposit(double d)
{
bankAccount::setBalance(bankAccount::getBalance()+d);
}
void checkingAccount::withdraw(double w)
{
bankAccount::setBalance(bankAccount::getBalance()-w);
}
void checkingAccount::getMonthlyStatement() const
{
bankAccount::getMonthlyStatement();
}
bankAccount.h:
#ifndef H_bankAccount
#define H_bankAccount
#include <string>
class bankAccount
{
public:
std::string getAcctOwnersName() const;
int getAcctNum() const;
double getBalance() const;
void getMonthlyStatement() const;
void setAcctOwnersName(std::string);
void setAcctNum(int);
void setBalance(double);
virtual void withdraw(double)=0;
virtual void deposit(double)=0;
private:
std::string acctOwnersName;
int acctNum;
double acctBalance;
};
#endif
bankAccount.cpp:
#include "bankAccount.h"
#include <iostream>
using std::string;
string bankAccount::getAcctOwnersName() const
{
return acctOwnersName;
}
int bankAccount::getAcctNum() const
{
return acctNum;
}
double bankAccount::getBalance() const
{
return acctBalance;
}
void bankAccount::setAcctOwnersName(string name)
{
acctOwnersName=name;
}
void bankAccount::setAcctNum(int num)
{
acctNum=num;
}
void bankAccount::setBalance(double b)
{
acctBalance=b;
}
void bankAccount::getMonthlyStatement() const
{
std::cout << "Name on Account: " << getAcctOwnersName() << std::endl;
std::cout << "Account Id: " << getAcctNum() << std::endl;
std::cout << "Balance: " << getBalance() << std::endl;
}
I know this is a lot of code to go through but can anyone help me understand why i cannot create an object from the class serviceChargeChecking the error is telling me that i cannot create an object from the abstract class but it doesn't seem to be abstract to me.
serviceChargeChecking implements void writeCheck(int), but the pure virtual function from checkingAccount has type void writeCheck(), so it's still pure in serviceChargeChecking, which makes the class abstract.
You have this in the abstract class checkingAccount:
virtual void writeCheck()=0;
but implement this in the derived class serviceChargeChecking:
void writeCheck(int);
The signature must be the same.
The writeCheck() method has different signatures in serviceChargeChecking and checkingAccount.
If you use C++11, use override in order to avoid this kind of error.
It's because your CheckingAcount has writeCheck() and serviceChargeChecking has writeCheck(int);
This probably due to the fact that you failed to Override checkingAccount's, writeCheck method, the abstract prototype was was
in checkingAccount class
virtual void writeCheck()=0;
and in serviceChargeChecking class
void writeCheck(int);
note the parameters, you didn't override checkingAccount's writeCheck you probably inherited it (implicitly), the serviceChargeChecking made a new writeCheck with an int parameter.
guys, I have the following code, but I'm getting error at compiling time... the error is at the end. Thanks
1st Class is "Person"
#ifndef PERSON_H//protecting .h files
#define PERSON_H//protecting .h files
#include <iostream>
#include <string>
using namespace std;
class Person
{
public:
Person();
Person(string first, string last)
{
firstName = first;
lastName = last;
}
virtual void setName(string first, string last)
{
firstName = first;
lastName = last;
}
virtual void setWeightAge(int w, int a)
{
weight = w;
age = a;
}
virtual string getFirstName()
{
return firstName;
}
virtual string getLastName()
{
return lastName;
}
virtual int getWeight()
{
return weight;
}
virtual int getAge()
{
return age;
}
virtual void printPerson()
{
cout << "Name: " << firstName << " " << lastName << endl;
cout << "Age: " << age << endl;
cout << "Weight: " << weight << endl;
}
protected:
string firstName, lastName;
int weight, age;
};
#endif
2nd Class is "Student"
#ifndef STUDENT_H//protecting .h files
#define STUDENT_H//protecting .h files
#include <iostream>
#include <string>
#include "Person.h"
using namespace std;
class Student : public Person
{
public:
Student();
Student(Person s)
{
sStudent = s;
}
virtual void setGPA(double g)
{
gpa = g;
}
virtual void setSchedule(string c, string t, string d)
{
stClass = c;
time = time;
days = d;
}
virtual void setGrade(char g)
{
grade = g;
}
virtual double getGPA()
{
if (grade == 'a') { gpa = 4.0; }
if (grade == 'b') { gpa = 3.0; }
if (grade == 'c') { gpa = 2.0; }
else gpa = 0;
return gpa;
}
virtual char getGrade()
{
return grade;
}
virtual void printSchedule()
{
cout << "Class | Days | Time " << endl;
cout << stClass << " | " << days << " | " << time << endl;
}
protected:
string stClass, time, days;
char grade;
double gpa;
Person sStudent;
};
#endif
and Main()
#include <iostream>
#include "Student.h"
using namespace std;
int main()
{
//creating a person
Person john("John", "Smith");
john.setWeightAge(180, 39);
john.printPerson();
//making john a student
Student johnStdntMath(john);
johnStdntMath.setSchedule("Math", "7:45", "M, W");
johnStdntMath.setGrade('b');
johnStdntMath.printPerson();
johnStdntMath.printSchedule();
system("pause");
return 0;
errors:
1>------ Build started: Project: Person, Configuration: Debug Win32 ------
1> main.cpp
1>main.obj : error LNK2019: unresolved external symbol "public: __thiscall Person::Person(void)" (??0Person##QAE#XZ) referenced in function "public: __thiscall Student::Student(class Person)" (??0Student##QAE#VPerson###Z)
1>c:\users\jorge\documents\visual studio 2010\Projects\Person\Debug\Person.exe : fatal error LNK1120: 1 unresolved externals
}
I suggest you double check your is-A and has-A relationships.
Writing Student : public Person says that a Student is-A Person. But later, you have a member variable sStudent of type Person, which says a Student has-A Person, and I'm guessing is not what you really want.
Check out the answers to this question: Inheritance vs. Aggregation for better explanations.
Listen to your linker, it's just as it says: In constructor Student::Student(Person) you're referring to constructor Person::Person(), but you didn't define Person::Person(), not in a way the linker can see when it does its thing with the Student constructor.
Technically, because you are filling in sStudent in the Student constructor's body the compiler first default-initializes the Person object sStudent, and then assigns to it s, the Person parameter of the constructor. If you'd use the initializer list then the Person member wouldn't be default-initialized and then assigned to but rather copy-constructed right away:
Student(const Person& s) : sStudent(s) { }
But the question remains: Why are you publicly declaring a default constructor in Person and not define it?
Also, you have a leak in Student. The string and Person members of Student won't clean up because when a Student object destructs its destructor won't be called. The Person destructor will be called, but not the Student destructor, and the reason being that the destructor of Person is non-virtual.
One more thing: It's a bad idea in object-oriented design in general and C++ in particular to use inheritance for reuse. The reason is that this very often leads to a violation of the LSP. It can also bear a (not major but nonetheless) performance overhead for introducing a virtual table. But it's the correctness that suffers that matters when you pick inheritance when you should really be using delegation.
You are accessing the no argument constructor for Person when you create the johnStdntMath instance. You need to either
Implement Person::Person() or ...
Change Student::Student(Person s) to Student::Student(Person const& s)
There are some other problems in your code as well. Student is-a Person so there is no need for the Student class to have a Person member variable - it shares the instance variables of its base class by virtue of inheritance. In other words, Student extends Person so your program could be written:
int main() {
Student johnStdntMath;
johnStdntMath.setName("John", "Smith")
johnStdntMath.setWeightAge(180, 39);
johnStdntMath.setSchedule("Math", "7:45", "M, W");
johnStdntMath.setGrade('b');
johnStdntMath.printPerson();
johnStdntMath.printSchedule();
return 0;
}
I would also avoid the using namespace std; statement anywhere and especially in a header file. For example, your Student class contains a member variable named time. This will conflict with the std::time_t std::time(std::time_t*) function defined in <ctime> if that header is included before "student.h".
You haven't implement the default constructor Person(),you can write it like this:
Person():weight(0)
,age(0){};
If you just want to complier it, this is enough;
Here are some tips below:
1.Check your mind, does class Student really need a Person member. If you really need it, Student(Person) may add an explicit symbol:
explicit Student(const Person& s) : sStudent(s) {...};
2.In Person.h
protected:
string firstName, lastName;
int weight, age;
the protected may be private?