I'm just starting out with OOP in C++ and I keep getting "base class undefined error". I'm coding a project that is basically a Library, but using classes. Google hasn't really been helping much because it seems that most of the time the error happened for other people was circular references in writing their own headers.
Here is the program(excuse the lengthiness, I crammed everything into one file for the time being)
driverLibrary.cpp:
#include "stdafx.h"
#include <iostream>
using namespace std;
class LibraryItem :public Borrowable{
public:
LibraryItem(string name, int id) :identifier(name), id(id){}
LibraryItem();
~LibraryItem();
string getIdentifier(){
return identifier;
}
int getId(){
return id;
}
bool borrow(){ return false; }
bool canBorrow() { return false; }
bool operator== (LibraryItem &comparison)
{
return (comparison.getId() == this->id);
}
protected:
string identifier;
int id;
};
class Borrowable{//interface
public:
bool isIn;
virtual bool borrow() = 0;
virtual bool canBorrow() = 0;
};
class Book :public LibraryItem, public Borrowable{ //all children will be borrowed the same way unless specified in their own class
public:
Book(string name, int id, string author, string genre) :author(author), genre(genre){ LibraryItem(name, id); }
Book(string name, int id, string author){ LibraryItem(name, id); this->author = author; }
string getAuthor(){ return author; }
string getGenre(){ return genre; }
//override
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
string author;
string genre;
bool isIn;//override
};
class Newspaper : public Media{
public:
Newspaper(string name, int id, int vol, int issue) : vol(vol), issue(issue){ LibraryItem(name, id); }
int getVol(){ return vol; }
int getIssue(){ return issue; }
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
int vol;
int issue;
bool isIn;
};
class Reference : public Book{//, public Borrowable{
public:
Reference(string name, int id, string author, int vol, int issue, string topic) : vol(vol), issue(issue), topic(topic), Book(name, id, author){}
int getVol(){ return vol; }
int getIssue(){ return issue; }
// bool borrow(){ return false; }
// bool canBorrow(){ return false; }
protected:
int vol;
int issue;
string topic;
};
class Magazine : public Media, public Borrowable{
public:
Magazine(string name, int id, string title, string publisher, int date);
};
class Media : public LibraryItem, public Borrowable{
public:
Media(string name, int id, string title, string publisher) : title(title), publisher(publisher), LibraryItem(name, id){}
bool borrow(){
if (!isIn) return false;
else isIn = false;
return true;
}
bool canBorrow(){ return isIn; }
protected:
string title;
string publisher;
bool isIn;
};
class CD :public Media{
public:
CD(string name, int id, string title, string publisher, int length, string artist) :length(length), artist(artist), Media(name, id, title, publisher) {}
int getLength(){ return length; }
string getArtist(){ return artist; }
protected:
int length;
string artist;
};
class DVD : public Media{
public:
DVD(string name, int id, string title, string publisher, int dpi) : dpi(dpi), Media(name, id, title, publisher) {}
int getDPI(){ return dpi; }
protected:
int dpi;
};
int main()
{
Book book = Book("Identifier", 234, "Mike Hunt");
return 0;
}
And here is the error log:
Error 1 error C2504: 'Borrowable' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 8 1 ConsoleApplication2
Error 2 error C2504: 'Media' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 53 1 ConsoleApplication2
Error 3 error C2504: 'Media' : base class undefined c:\users\connor\documents\visual studio 2013\projects\consoleapplication2\consoleapplication2\driverlibrary.cpp 81 1 ConsoleApplication2
4 IntelliSense: no default constructor exists for class "Media" c:\Users\Connor\Documents\Visual Studio 2013\Projects\ConsoleApplication2\ConsoleApplication2\driverLibrary.cpp 55 77 ConsoleApplication2
You need to declare (and in some cases, define) classes before they are used. This is just like variables, functions, and anything else in C++.
You should be able to fix the first three errors that the compiler is reporting by moving the definition of Borrowable to the top of your file and putting Media right after LibraryItem.
The fourth error is because Newspaper doesn't explicitly call a constructor for Media, and Media has no default constructor that the compiler can insert a call to.
C++ type's visibility extend from the point they are first declared forward. Order matters, it is an inherited trait of the C language, based on "textual" treatment of include files as opposed to true modules or multi file type metadata, where the compiler traditionally notes each type as it is declared syntactically, stores it in a symbol table, where it is immediately available.
This differs from Java or C# compilers which parse the whole source file first, then resolve types and symbols later, removing order from the equation.
To allow cyclical relationships in C++ there is a feature called a forward declaration. It allows you to declare pointer types to a type that hasn't yet been defined (note declared is different from defined).
class A; // declaration
class B {
class A * a; // refers to A, but does not use any members within A yet
};
class A { // definition
int size;
};
Related
I was working on homework that my instructor wanted me to write a class named Species with setter and getter functions. I wrote that code but I can't set or get any value when I run it. Can you help me?
class Species
{
private:
string name;
string country;
int population;
int growthrate;
public:
int year;
void setName(string NameS){
NameS=name;
}
void setCountry(string CountryS){
CountryS=country;
}
void setPopulation(int pop){
pop=population;
}
void setGrowthRate(int GrowRth){
GrowRth=growthrate;
}
void setYear(int syear){
syear=year;
}
string getName() {
return name;
}
string getCountry() {
return country;
}
int getPopulation() {
return population;
}
int getGrowthrate() {
return growthrate;
}
double e=2.71828182;
double calculatePopulation() {
int b=growthrate*year;
int a=pow(e,b);
return population*a;
}
};
First of all. Your class has fields like:
string name;
string country;
int population;
int growthrate;
And your methods are like:
void setName(string NameS){
NameS=name;
}
So you want to set NameS value to the name which makes no sense.
You should assign the field like name to be equal to nameS not the opposite.
Generally, a setter should look like this.
void setVariable(const VariableType& var){
this->var=var;
}
What you did was var=this->var.
Btw, you should make your getter-s const
You should use "this" keyword to set the value to object of the class.
this: to refer current class instance variable. The this keyword can be used to refer current class instance variable.
for example:
void setName(string name){
this.name=name;
}
void setGrowthRate(int growthrate){
this.growthrate=growthrate;
"this" is very helpful in please learn more about it.
Okay, so I have an assignment for a class that requires us to use a series of classes together, to simulate a police officer issuing a ticket.
Here's how it works:
ParkedCar class:
To know the cars make, model, color, license number, and the number of minutes
that the car has been parked
ParkingMeter Class:
know how much time has been purchased
ParkingTicket Class:
know make, model, color, license of the car, calculate the fine, as well as the name and badge number of the officer issuing the ticket
PoliceOfficer Class:
Know the name a badge number of the officer
AND
Examine ParkedCar and ParkingMeter objects and determine if a ticket is needed, if so, generate a ParkingTicket object.
Here's what code I have so far:
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<ctime>
using namespace std;
class ParkedCar
{
string sMake;
string sModel;
string sColor;
string sPlate;
int iMinsParked;
public:
ParkedCar();
string getMake() const
{ return sMake; }
void setMake(string temp)
{ sMake = temp; }
string getModel() const
{ return sModel; }
void setModel(string temp)
{ sModel = temp; }
string getColor() const
{ return sColor; }
void setColor(string temp)
{ sColor = temp; }
string getPlate() const
{ return sPlate; }
void setPlate(string temp)
{ sPlate = temp; }
int getMins() const
{ return iMinsParked; }
};
ParkedCar::ParkedCar()
{
srand(time(NULL));
iMinsParked = (rand() % 10000);
}
class ParkingMeter
{
int iMinsPurch;
public:
void setMins(int temp)
{ iMinsPurch = temp; }
int getMins() const
{ return iMinsPurch; }
}
class Ticket : public ParkedCar
{
public:
string getName()
{ return sName; }
int getBadge()
{ return iBadge; }
};
class Officer
{
string sName;
int iBadge;
public:
friend string Ticket::getName();
//{ return sName; }
friend int Ticket::getBadge();
//{ return iBadge; }
};
int main()
{
ParkedCar Park;
cout << endl << endl;
cout << Park.getMins();
cout << endl << endl;
return 0;
}
Where I'm confused is mostly on the Ticket and Officer classes. The assignment clearly wants Ticket to have it's own information from all the other classes, but I'm not sure how to pass that information along. I've tried making it a child class of ParkedCar, but I just get a multiple definitions error. And I can't get the friend functions to work. I've tried them both ways and if I make them within Ticket, it tells me Officer isn't defined. And I'm really confused on how I'm supposed to write code for Officer generating an instance of Ticket when nothing has actually been initialized yet.
So:
How do I get all the information into the Ticket class?
How would I get Officer to generate an instance of Ticket?
Please keep in mind this is a STUDENT assignment, not something professional. I just want to do what the assignment says. I'm not interested in ways "around" the problem, because that's not what the prof wants.
Thanks in advance for your time. :D
Firstly: learn to use constructors. All this stuff you're setting...it is integral to the identity of a car, or a cop, etc. It should have been provided when the object was built. C++ isn't Java; quit treating classes like Java beans. :P
Secondly, a Ticket is not a ParkedCar. It associates with a car, but is not one itself. Consider instead:
class Ticket {
ParkedCar violator;
Officer issuer;
public:
Ticket(const Officer &cop, const ParkedCar &car) :
violator(car), issuer(cop) {
}
ParkedCar getCar() { return violator; }
Officer getOfficer() { return issuer; }
// Note, no mutators here!
// The biggest reason you had to have mutators, is that your construction
// was incomplete.
// The info associated with a Ticket should not be modified once the ticket
// is written. And since the constructor has all the info needed, there's no
// need to provide a way to modify them.
};
So an Officer doesn't need to know about the potentially-intricate details of a car, or exactly what info a Ticket needs. He can just hand himself and the car over to the constructor, and trust that it will extract whatever info it needs. (In this case, we just store copies of both items.)
class Officer {
std::string name;
int badge_number;
public:
Officer(const std::string& name, int badge) : name(name), badge_number(badge) { }
public std::string getName() { return name; }
public int getBadgeNumber() { return badge_number; }
Ticket writeTicketFor(const ParkedCar &violator) {
return Ticket(*this, violator);
}
};
I'm trying to invoke my parent class's constructor that has arguments, in my child class's constructor with arguments, but I get a compiler error "expected primary expression before ...".
This is what I have:
class Ship {
private:
string shipName;
int yearBuilt;
public:
Ship();
Ship(string name, int year);
};
class CruiseShip: public Ship {
private:
int maxPeople;
public:
CruiseShip()
: Ship() {
maxPeople = 100;
}
CruiseShip(int m)
: Ship(string name, int year) {
maxPeople = m;
}
};
Ship::Ship() {
shipName = "Generic";
yearBuilt = 1900;
}
Ship::Ship(string name, int year) {
shipName = name;
yearBuilt = year;
}
And this is the specific piece of code I'm having trouble with:
CruiseShip(int m)
: Ship(string name, int year) {
maxPeople = m;
}
My goal is to be able to create an object, CruiseShip c1 with 3 arguments that set the name,year, & max people.
I've been reading online and it tells me that this should be ok, but I'm obviously doing something wrong. I'd appreciate any input, thanks!
You need to pass parameters to parent class constructor like this:
CruiseShip(int m, string name, int year): Ship(name, year), maxPeople(m) {}
Better, you should set maxPeople to m in the initializer list.
I have an object, every member variable in this object has a name which I can acquire it by calling get_name() ,what I want to do is concatenate all the names of the member variables in alphabetical order, then do something. for example:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
}
//skip the get_name(), set_name() and others
private:
string m_local_name;
T m_type_var;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
...
}
I have to hard-code like this:
object o;
string sign = o.m_base.get_name();
sign += o.m_team.get_name();
I need a function to do this instead of copying and pasting when the object varies. Anyone has an idea?
One way to do this in normal C++, provided all of the members belong to the same class or are derived from some base class will be to use variable number of arguments to a function. An example follows.
#include <stdarg.h>
string concatenateNames(int numMembers, ...)
{
string output;
va_list args;
va_start(args, numMembers);
for(int i = 0; i < numMembers; i++)
{
MemberClass *pMember = va_arg(args, MemberClass*);
output += pMember->get_name();
}
va_end(args);
return output;
}
class Object
{
public:
MemberClass x;
MemberClass y;
MemberClass z;
};
int main()
{
Object o;
string sign = concatenateNames(3, &o.x, &o.y, &o.z);
}
If the types of all the members are different, you can look into variadic templates of C++11x: http://en.wikipedia.org/wiki/Variadic_Templates, but I can't seem to find a way to do otherwise.
If variables which have name have a same type (or these types belongs one hierarchy) you can use map of these vars. Is not good way, but maybe it helps you
Example
class object
{
public:
object() //: m_team("team"), m_base("base")
{
this->vars["m_team"] = CXMLWrapper<string>("team");
//.....
}
public:
map<string, CXMLWrapper<string> > vars;
/*CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;*/
...
}
object o;
string sign;
for(auto& x : o.vars)//i cannot remember syntax of for of map
sign += x.get_name;
PS Sorry for my writing mistakes. English in not my native language.
One method is to have an external library of member names which the CXMLWrapper class updates:-
class BaseXMLWrapper
{
public:
void ListMembers (const char *parent)
{
// find "parent" in m_types
// if found, output members of vector
// else output "type not found"
}
protected:
void RegisterInstance (const char *parent, const char *member)
{
// find 'parent' in m_types
// if not found, create a new vector and add it to m_types
// find 'member' in parent vector
// if not found, add it
}
private:
static std::map <const std::string, std::vector <const std::string> >
m_types;
};
class CXMLWrapper <class T, const char *parent> : BaseXMLWrapper
{
public:
CXMLWrapper(const char* p_name) : m_local_name(p_name)
{
RegisterInstance (parent, p_name);
}
// you could override assignments, copy and move constructors to not call RegisterInstance
//skip the get_name() set_name()
private:
m_local_name;
}
class object
{
public:
object() : m_team("team"), m_base("base")
{
}
public:
CXMLWrapper<string, "object"> m_team;
CXMLWrapper<string, "object"> m_base;
...
};
This does add overhead to the construction of objects, but as it's only a constructor overhead it might not affect overall system performance much.
This looks like a "observe pattern", you just need to keep a single copy in object as a member variable "string name_;", and pass the name_s's reference into CXMLWrapper like this:
class CXMLWrapper<class T>
{
public:
CXMLWrapper(const string &name)
: local_name_(name)
{
}
//skip the get_name() set_name()
private:
const string &local_name_;
}
class object
{
public:
object()
: team_("team"),
base_("base"),
m_team(team_)
, m_base(base_)
{
}
public:
string team_;
string base_;
CXMLWrapper<string> m_team;
CXMLWrapper<string> m_base;
}
I'm new to C++, and I'm trying to write a simple code to compare two objects of subclasses of a parent class called Comparable. I want each subclass to have its own implementation of a method to compare objects based on the data they hold, so I used the virtual keyword:
class Comparable {
public:
virtual int compare(Comparable *other);
};
For example, my subclass HighScoreElement would have its own implementation of compare that would compare the score of the object to the score of another HighScoreElement.
Here is my subclass HighScoreElement:
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(string user_name, int user_score); // A constructor
private:
int score;
string name;
};
But in my compare implementation in HighScoreElement, I first try to check if the current object's data is the same as other's data. But since the pointer to other is of class Comparable and not HighScoreElement, I can't reference other->score at all in my code, even though HighScoreElement is a subclass of Comparable.
Here is the full code so far:
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other);
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
if (this->score == other->score) { // Compiler error right here, other->score is invalid.
// Code to do the comparing if two scores are equal...
}
}
I get a compiler error immediately when I write this code:
if (this->score == other->score)
because other doesn't have data called score, but its subclass, HighScoreElement, does. How can I fix my function implementation so that I can reference the data of "other?" I know my question may sound vague, but any help would be appreciated!
You could implement a virtual function GetScore(), possibly pure virtual in the base class, and use that instead of accessing the field score in your compare function. Make it a const method. On the other hand, Compare could be a method implemented in the base class, that uses this->GetScore() and other->GetScore()
Code stub:
class A {
virtual int getScore() const = 0;
inline bool compare(const A* in) {return (in && this->getScore() == in->getScore());}
//return false also if "in" is set to NULL
}
class B : public A {
int score;
inline int getScore() const {return score;}
}
You can cast the pointer passed to HighScoreElement::compare using "dynamic_cast" (it throws a bad_cast exception on failure).
int HighScoreElement::compare(Comparable *other) {
HighScoreElement *h = NULL;
try
{
ptr = dynamic_cast<HighScoreElement *>(other);
}
catch(std::bad_cast const &)
{
// Handle the bad cast...
}
if (this->score == ptr->score) {
// Code to do the comparing if two scores are equal...
}
}
If you are prepared to accept null pointers, you can use dynamic casts. You can have an overload for the case when you are comparing a HighScoreElement pointer to avoid an unnecessary cast.
#include <iostream>
using namespace std;
class Comparable {
public:
virtual int compare(Comparable *other) = 0; // made pure virtual to compile without definition
};
class HighScoreElement: public Comparable {
public:
virtual int compare(Comparable *other);
int compare(HighScoreElement *other); // comparing to a HighScoreElement ptr, no need to dynamic cast
HighScoreElement(int user_score, string user_name);
private:
string name;
int score;
};
HighScoreElement::HighScoreElement(int user_score, string user_name) {
name = user_name;
score = user_score;
}
int HighScoreElement::compare(Comparable *other) {
HighScoreElement * pHSE = dynamic_cast<HighScoreElement*>(other);
if (pHSE) {
return compare(pHSE);
} else {
return -1; // or however you want to handle compare to non HighScoreElement
}
}
int HighScoreElement::compare(HighScoreElement *other) {
if (this->score == other->score) {
;
}
}
Are you sure it's not
compare( Comparable other )
If (this->score == other.score)