I have 3 c++ files, instrument.h, percussion.h, and instrumentApp.cpp. Instrument.h is the base class and percussion.h inherits it. Percussion objects are defined and implemented in the instrumentApp.cpp class. Whenever I run instrumentApp.cpp, I get the segmentation fault error.
I have managed to trace the cause of the error to the overloaded << operator function in percussion.h where I am calling a method of the base class instrument.h. For some reason, my code is unable to call methods of the base class and I don't know why. Can you please help me?
Here is the instrument.h class
#ifndef INSTRUMENT_H
#define INSTRUMENT_H
class Instrument{
private:
std::string name;
std::string sound;
std::string lowRange;
std::string highRange;
public:
Instrument(std::string name, std::string sound, std::string lowRange, std::string highRange){
this->name = name;
this->sound = sound;
this->lowRange = lowRange;
this->highRange = highRange;
}
std::string getName() const{
return this->name;
}
std::string play()const {
return this->sound;
}
std::string getLowRange() const{
return this->lowRange;
}
std::string getHighRange() const{
return this->highRange;
}
bool isWind();
bool isWoodWind();
bool isBrass();
bool isKeyboard();
bool isPercussion();
bool isStrings();
friend std::ostream &operator <<(std::ostream &os, const Instrument &instrument){
}
};
#endif
Here is the percussion.h class
#ifndef PERCUSSION_H
#define PERCUSSION_H
#include "instrument.h"
class Percussion : public Instrument{
private:
bool struck;
public:
Percussion(std::string name, std::string sound, std::string lowRange, std::string highRange, bool struck) : Instrument(name,sound,lowRange,highRange){
this->struck=struck;
}
bool isStrucked() const {
return this->struck;
}
bool isPercussion() {
return true;
}
std::string getType() const{
if(this->struck){
return "struck";
}
else{
return "";
}
}
friend std::ostream &operator <<(std::ostream &os, Percussion &percussion){
//The error stems from this line of code
//Apparently, the getName() method in the base class isn't called
os<<percussion.getName();
}
};
#endif
Here is the implementation file instrumentApp.cpp
#include <iostream>
#include <string>
#include <sstream>
#include <cstdlib>
#include "instrument.h"
#include "percussion.h"
#include "strings.h"
using namespace std;
int main() {
Percussion timpani("timpani", "boom", "D2", "A2", true);
cout << timpani << endl;
Percussion harp("harp", "pling", "Cb1", "F#7", false);
cout << harp << endl;
return 0;
}
The problem here is that I wasn't returning the os object when I overloaded the << operator.
The fix is as follows in the percussion.h file
friend std::ostream &operator <<(std::ostream &os, Percussion &percussion){
os<<percussion.getName();
return os;
}
Related
I managed to fix the error two different ways but I honestly don't know why it works. Can someone here please provide some clarification?
As is, the following code gives me the following errors
Error LNK2005 "public: __thiscall Person::Person(class std::basic_istream<char,struct std::char_traits<char> > &)" (??0Person##QAE#AAV?$basic_istream#DU?$char_traits#D#std###std###Z) already defined in Person_Functions.obj
Error LNK1169 one or more multiply defined symbols found
Program:
//**************
//Person_Class.h
//**************
#ifndef PERSON_CLASS_H
#define PERSON_CLASS_H
#include <iostream>
#include <string>
using namespace std;
struct Person {
string name;
string address;
string getName() const { return name; }
string getAddress() const { return address; }
Person() = default;
Person(string n, string a) : name(n), address(a) {}
Person(istream& is);
};
ostream& print(ostream&, const Person&);
istream& read(istream&, Person&);
Person::Person(istream& is) { read(is, *this); }
#endif
//********************
//Person_Functions.cpp
//********************
#include "Person_Class.h"
istream& read(istream& is, Person& p) {
is >> p.name >> p.address;
return is;
}
ostream& print(ostream& os, const Person& p) {
os << p.getName() << " " << p.getAddress();
return os;
}
If I write the header like this instead, the errors go away
//**************
//Person_Class.h
//**************
#ifndef PERSON_CLASS_H
#define PERSON_CLASS_H
#include <iostream>
#include <string>
using namespace std;
//This seems like a "duct tape" fix, feels messy and unorganized.
struct Person;
istream& read(istream&, Person&);
struct Person {
string name;
string address;
string getName() const { return name; }
string getAddress() const { return address; }
Person() = default;
Person(string n, string a) : name(n), address(a) {}
Person(istream& is) { read(is, *this); }
//Defining istream constructor in the class definition fixes the issue
//but as you can see above, this forces me to declare read above the struct
//which means I have to then declare the struct above read
};
ostream& print(ostream&, const Person&);
#endif
//This uses the same Person_Functions.cpp as before
The other solution I found is to instead define the istream constructor inside Person_Functions.cpp
I am really confused about why the first version doesn't work. Is there a preferred way to handle this and can someone provide some clarification here on the differences?
Sorry for the long post. I wasn't sure how much detail to include. Thanks for taking the time to teach me!
I have only one custom class with .h and .cpp files but I get error while trying to create an instance of this class from main.cpp (using IDE clion).
I am just a beginner and reading C++ primer learning class, if there are some inappropriate things please point out.
main.cpp
#include "Fun.h"
void Solve();
int main()
{
Solve();
return 0;
}
void Solve()
{
Sales_data total;
if(read(cin,total)){ //read the first record
Sales_data temp;
while(read(cin,temp)){
if(temp.isbn() == total.isbn())
total.combine(temp);
else{
print(cout,total) << endl;
total = temp;
}
}
print(cout,total);
}//if
else{
cerr << "No data!?" << endl;
}
}
Fun.cpp
#include "Fun.h"
using std::istream;
using std::ostream;
double Sales_data ::avg_price() const {
if(units_sold)
return revenue/units_sold;
else
return 0;
}
Sales_data& Sales_data:: combine(const Sales_data& rhs){
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this;
}
istream &read(istream &is,Sales_data &item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price * item.units_sold;
return is;
}
ostream &print(ostream &os, const Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " "
<< item.revenue << " " << item.avg_price() ;
return os;
}
Sales_data add(const Sales_data& lhs,const Sales_data& rhs)
{
Sales_data sum = lhs;
sum.combine(rhs);
return sum;
}
Fun.h
#ifndef PROJECT1_FUN_H
#define PROJECT1_FUN_H
#include <cstdio>
#include <cstring>
#include <cassert>
#include <vector>
#include <iostream>
using std::istream;
using std::ostream;
using std :: cin;
using std :: cout;
using std :: cerr;
using std :: endl;
struct Sales_data{
std::string isbn()const{return bookNo;}
Sales_data& combine(const Sales_data&);
double avg_price() const;
std::string bookNo;
unsigned units_sold = 0;
double revenue = 0;
};
Sales_data add(const Sales_data&,const Sales_data&);
istream &read(istream &,Sales_data &);
ostream &print(ostream &,Sales_data &);
#endif //PROJECT1_FUN_H
This is the error information:
I wonder what caused the problem?
I think the problem is that declaration and definition of the print function are different (the Sales_data parameter is a reference in declaration while is a constant reference in definition):
ostream &print(ostream &,Sales_data &); // Fun.h
ostream &print(ostream &os, const Sales_data &item) // Fun.cpp
Change the declaration in the header file to:
ostream &print(ostream &, const Sales_data &);
When I try to run the class with the class counter.cpp, I get the following error
In file included from Bounded_Counter.h:7:0,
from counterApp.cpp:4:
Lower_Bounded_Counter.h:9:7: error: redefinition of âclass LowerBoundedCounterâ
Lower_Bounded_Counter.h:9:7: error: previous definition of âclass LowerBoundedCounterâ
In file included from Bounded_Counter.h:8:0,
from counterApp.cpp:4:
Upper_Bounded_Counter.h:9:7: error: redefinition of âclass UpperBoundedCounterâ
Upper_Bounded_Counter.h:9:7: error: previous definition of âclass UpperBoundedCounterâ
I am aware that I am including some classes twice, but I don't know how to find it. Can you please help me find what I am doing wrong? There are 4 classes Counter.h, LowerBoundedCounter.h, UpperBoundedCounter.h, and BoundedCounter.h. LowerBoundedCounter.h and UpperBoundedCounter.h both include the Counter.h file. BoundedCounter.h includes both the LowerBoundedCounter.h and the UpperBoundedCounter.h files. The implementation file is counterApp.cpp (not provided here)
Here is the Counter.h class.
#ifndef COUNTER_H
#define COUNTER_H
#include <iostream>
class Counter{
private:
int val;
public:
Counter():val(0) {}
Counter(int val):val(val){}
void up(){
this->val++;
}
void down(){
this->val--;
}
int getVal() const {
return this->val;
}
friend std::ostream &operator <<(std::ostream &os, const Counter &counter) {
os << "A Counter with a value of " << counter.val;
return os;
}
};
#endif
Here is LowerBoundedCounter.h class. This class contains a 'Counter' object.
#ifndef LOWER_BOUNDED_COUNTER_H
#define LOWER_BOUNDER_COUNTER_H
#include<iostream>
#include "Counter.h"
class LowerBoundedCounter{
private:
Counter counter;
int limit;
public:
LowerBoundedCounter(int limit,int val):counter(val), limit(limit){
}
LowerBoundedCounter(int val):counter(val),limit(10){
}
LowerBoundedCounter():counter(),limit(0){
}
void up(){
if(getVal() > limit){
counter.up();
}
}
void down(){
counter.down();
}
int getLimit() const{
return this->limit;
}
int getVal() const{
return counter.getVal();
}
friend std::ostream &operator <<(std::ostream &os, const LowerBoundedCounter &LowerBoundedCounter){
os << "An LowerBoundedCounter with a value of " << LowerBoundedCounter.getVal() << " and a limit of "<<LowerBoundedCounter.limit;
return os;
}
};
#endif
Here's the UpperBoundedCounter.h class
#ifndef UPPER_BOUNDED_COUNTER_H
#define UPPER_BOUNDER_COUNTER_H
#include<iostream>
#include "Counter.h"
class UpperBoundedCounter{
private:
Counter counter;
int limit;
public:
UpperBoundedCounter(int limit,int val):counter(val), limit(limit){
}
UpperBoundedCounter(int val):counter(val),limit(10){
}
UpperBoundedCounter():counter(),limit(10){
}
void up(){
if(getVal() < limit){
counter.up();
}
}
void down(){
counter.down();
}
int getLimit() const {
return this->limit;
}
int getVal() const{
return counter.getVal();
}
friend std::ostream &operator <<(std::ostream &os, const UpperBoundedCounter &UpperBoundedCounter){
os << "An UpperBoundedCounter with a value of " << UpperBoundedCounter.getVal() << " and a limit of "<<UpperBoundedCounter.limit;
return os;
}
};
Finally, I have objects from all 3 of the above classes in BoundedCounter.h
#ifndef BOUNDED_COUNTER_H
#define BOUNDER_COUNTER_H
#include<iostream>
#include "Counter.h"
#include "Lower_Bounded_Counter.h"
#include "Upper_Bounded_Counter.h"
class BoundedCounter{
private:
Counter counter;
UpperBoundedCounter upperBoundedCounter;
LowerBoundedCounter lowerBoundedCounter;
public:
BoundedCounter(int val, int upperLimit, int lowerLimit):counter(val),upperBoundedCounter(upperLimit),lowerBoundedCounter(lowerLimit){
}
BoundedCounter(int val,int upperLimit):counter(val), upperBoundedCounter(upperLimit), lowerBoundedCounter(){
}
BoundedCounter(int val):counter(val),upperBoundedCounter(),lowerBoundedCounter(){
}
BoundedCounter():counter(), upperBoundedCounter(), lowerBoundedCounter(){
}
void up(){
if(getVal() < upperBoundedCounter.getLimit() && getVal() > lowerBoundedCounter.getLimit()){
counter.up();
}
}
void down(){
counter.down();
}
int getLowerLimit() const{
return lowerBoundedCounter.getLimit();
}
int getUpperLimit() const{
return upperBoundedCounter.getLimit();
}
int getVal() const{
return counter.getVal();
}
friend std::ostream &operator <<(std::ostream &os, const BoundedCounter &BoundedCounter){
os << "An BoundedCounter with a value of " << BoundedCounter.getVal() << " and a lower limit of "<<BoundedCounter.getLowerLimit()
<<" and a higher limit of "<<BoundedCounter.getUpperLimit();
return os;
}
};
#endif
Your header protection macro is wrong in all header files.
#ifndef BOUNDED_COUNTER_H
#define BOUNDER_COUNTER_H
Typo 'R'
There is a smaller problem in the UpperBoundedCounter.h, which does not have the closing #endif . But this will cause another problem.
I try to write a simple Logger but the ofstream writes hex instead of the characters to the file.
Definition:
#pragma once
#include <iostream>
#include <fstream>
#include <string>
#define LOG Logger::getInstance()
class Logger
{
public:
static Logger m_instance;
static Logger &getInstance()
{
if (m_logfile == nullptr)
{
m_logfile = new std::ofstream(m_logfile_string.c_str(),
std::ofstream::out | std::ofstream::app);
}
return m_instance;
}
Logger &operator<<(const std::string &c);
Logger &operator<<(const char c[]);
private:
static std::ofstream *m_logfile;
static std::string m_logfile_string;
Logger() {};
Logger(const Logger &) = delete;
Logger(Logger &&other) = delete;
Logger &operator=(const Logger &other) = delete;
Logger &operator=(Logger &&other) = delete;
~Logger()
{
if (m_logfile != nullptr)
m_logfile->close();
};
std::string currentDateTime() const;
};
Impl.
#include "Logger.h"
#include <iostream>
#include <ctime>
Logger Logger::m_instance;
std::ofstream *Logger::m_logfile = nullptr;
std::string Logger::m_logfile_string = "log.txt";
Logger &Logger::operator<<(const std::string &c)
{
this->operator<<(c.c_str());
return *this;
}
Logger &Logger::operator<<(const char c[])
{
std::cout << currentDateTime() << " - "
<< c << std::endl;
m_logfile->operator<<(c);
return *this;
}
// Get current date/time, format is YYYY-MM-DD.HH:mm:ss
std::string Logger::currentDateTime() const
{
auto now = time(nullptr);
struct tm tstruct;
char buf[80];
tstruct = *localtime(&now);
strftime(buf, sizeof(buf), "%Y-%m-%d.%X", &tstruct);
return buf;
}
Usage:
#include "Logger.h"
void main()
{
LOG << "started"; // Logger::getInstance() << "started";
}
Outcome:
00007FF696EF3C00 in the log.txt The console output is right.
Whats going wrong here?
You use member function of iostream:
m_logfile->operator<<(c);
There is no member function operator<<(char* c), but there is operator<<(void* p), so pointer is implicitly converted. See documentation on ostream.
Operators for char* are not class member functions:
ostream& operator<< (ostream& os, const char* s);
See here: operator<< (ostream)
So you need this code:
operator<<(*m_logfile, c);
Or much more cleaner:
(*m_logfile) << c;
Test example:
#include <iostream>
int main() {
std::cout.operator<<("test");
operator<<(std::cout, "test");
std::cout << "test";
}
Prints 0x400944testtest.
If you use
(*m_logfile)<<c;
instead of
m_logfile->operator<<(c);
It will work.
Reason:
Your syntax calls the member function ostream::operator<<() which is not defined for char* nor for string. It's only defined for void* which always displays address in hex.
The classic syntax calls here the non member function ostream std::operator<<(...) which has overloads for string and char*
I've looked up information for overloading the << operator, and it seems like I did everything correctly, but I keep getting a compile error. I've friended this function in my header file, and placed a prototype at the top of my cpp file.
My University.h:
#ifndef UNIVERSITY_H
#define UNIVERSITY_H
#include <string>
#include <vector>
#include <iostream>
using namespace std;
#include "Department.h"
#include "Student.h"
#include "Course.h"
#include "Faculty.h"
#include "Person.h"
class University
{
friend ostream& operator<< (ostream& os, const vector<Department>& D);
friend ostream& operator<< (ostream& os, const Department& department);
protected:
vector<Department> Departments;
vector<Student> Students;
vector<Course> Courses;
vector<Faculty> Faculties;
static bool failure;
static bool success;
public:
bool CreateNewDepartment(string dName, string dLocation, long dChairID);
bool ValidFaculty(long dChairID);
};
#endif
My University.cpp:
#ifndef UNIVERSITY_CPP
#define UNIVERSITY_CPP
#include<string>
#include<vector>
#include<iostream>
using namespace std;
#include "University.h"
ostream& operator<<(ostream& os, const vector<Department>& D);
ostream& operator<<(ostream& os, const Department& department);
bool University::failure = false;
bool University::success = true;
bool University::CreateNewDepartment(string dName, string dLocation, long dChairID)
{
if((dChairID != 0) && (ValidFaculty(dChairID)== University::failure))
{
Department D(dName, dLocation, dChairID);
Departments.push_back(D);
for (int i = 0; i < Departments.size(); i++)
cout << Departments;
return University::success;
}
return University::failure;
}
bool University::ValidFaculty(long dChairID)
{
for (int i = 0; i < Faculties.size(); i++)
{
if (Faculties[i].ID == dChairID)
return University::success;
}
return University::failure;
}
ostream& operator<<(ostream& os, const vector<Department>& D)
{
for (int i = 0; i < D.size(); i++)
os << D[i] << endl;
os << "\n";
return os;
}
ostream& operator<< (ostream& os, const Department& department)
{
department.Print(os);
return os;
}
#endif
My Department.h:
#ifndef DEPARTMENT_H
#define DEPARTMENT_H
#include<vector>
#include<string>
#include<iostream>
using namespace std;
class Department
{
friend class University;
friend ostream& operator<< (ostream& os, Department& department);
protected:
long ID;
string name;
string location;
long chairID;
static long nextDepartID;
public:
Department();
Department(string dName, string dLocation, long dChairID);
void Get();
void Print(ostream& os)const;
};
#endif
My Department.cpp:
#ifndef DEPARTMENT_CPP
#define DEPARTMENT_CPP
#include<iostream>
#include<string>
using namespace std;
#include "Department.h"
long Department::nextDepartID = 100;
Department::Department()
{
ID = nextDepartID++;
name = "Null";
location = "Null";
chairID = 0;
}
Department::Department(string dName, string dLocation, long dChairID):name(dName), location(dLocation), chairID(dChairID)
{
ID = nextDepartID++;
}
void Department::Get()
{
}
void Department::Print(ostream& os)const
{
os << "\n";
os << ID << endl;
os << name << endl;
os << location << endl;
os << chairID << endl;
os <<"\n\n";
}
ostream& operator<< (ostream& os, const Department& department)
{
department.Print(os);
return os;
}
#endif
Now everything can be seen that pertains only to this problem. The only error I receive now is that void value is not being ignored.
Snippet of error:
University.cpp: In function ‘std::ostream& operator<<(std::ostream&, const Department&)’:
University.cpp:53: error: void value not ignored as it ought to be
Department.cpp: In function ‘std::ostream& operator<<(std::ostream&, const Department&)’:
Department.cpp:42: error: void value not ignored as it ought to be
FINAL EDIT:
Thanks to everyone that helped me. I definitely have a better understanding of operator overloading now...especially when it deals with printing vectors of user-defined types!
The complaint was that while your function to iterate over and print the vector contents may have been correct, the actual object contained by the vector did not have an operator<< specified.
You need to have one.
If you already have a method called Print() in your Department class, you could simply create an overload for operator<< as follows:
std::ostream& operator<<(std::ostream& os, const Department& department) {
os<<department.Print();
return os;
}
I had prepared the following code before you posted your update. Maybe it can help you.
#include<iostream>
#include<vector>
#include<string>
class Department {
public:
Department(const std::string& name)
: m_name(name) { }
std::string name() const {
return m_name;
}
private:
std::string m_name;
};
// If you were to comment this function, you would receive the
// complaint that there is no operator<< defined.
std::ostream& operator<<(std::ostream& os, const Department& department) {
os<<"Department(\""<<department.name()<<"\")";
return os;
}
// This is a simple implementation of a method that will print the
// contents of a vector of arbitrary type (not only vectors, actually:
// any container that supports the range-based iteration): it requires
// C++11.
template<typename T>
void show(const T& container) {
for(const auto& item : container) {
std::cout<<item<<std::endl;
}
}
int main() {
std::vector<Department> deps = {{"Health"}, {"Defense"}, {"Education"}};
show(deps);
}
Compile with g++ example.cpp -std=c++11 -Wall -Wextra (I used OS X 10.7.4 and GCC 4.8.1) to get:
$ ./a.out
Department("Health")
Department("Defense")
Department("Education")