Defining << operator at a base class - c++

I'm trying to define the << operator for a base class, so I can later print the identifier of each object easily.
I have tried an SSCCE, but I don't really know where the problem is, since I'm printing a direction and not the content. I don't know if the problem appears by printing the vector position, or by printing the std::string(char[]).
main.cpp:
#include "City.h"
#include <vector>
#include <iostream>
int main() {
std::vector<Location*> locations;
locations.push_back(new City("TEST"));
for(unsigned int it = 0; it<locations.size(); it++){
std::cout << locations[it] << std::endl;
}
return 0;
}
Location.h:
#include <cstring>
#include <string>
class Location {
public:
Location(const std::string id);
friend std::ostream& operator<<(std::ostream& os, Location& loc);
std::string GetId();
private:
// Name/identifier of the location
char ID[5];
};
Location.cpp:
#include "Location.h"
Location::Location(const std::string id){
memset(this->ID, 0, 5);
strncpy(this->ID, id.c_str(), 5); // I have it as a char[5] at a larger app
}
std::string Location::GetId(){
return std::string(this->ID);
}
std::ostream& operator<<(std::ostream& os, Location& loc){
os << loc.GetId();
return os;
}
City.h:
#include "Location.h"
class City: public Location{
public:
City(std::string id);
};
City.cpp:
#include "City.h"
City::City(const std::string id) : Location(id){
}
Any idea?

Related

Construct two classes that has attributes and can use methods of each other

I'd like to know is it possible that two classes has attributes and can use methods of each other. For example, there're a class STUDENT and a class COURSE, a STUDENT have a list of joined courses and a COURSE have list of participants(students). I tried this:
in STUDENT.h
#include <iostream>
#include <vector>
// #include "COURSE.h"
class COURSE;
class STUDENT {
string name;
std::vector<COURSE*> listCourses;
public:
STUDENT(){};
addCourse(COURSE* &course){
listCourses.push_back(course);
course.addStudent(this);
}
string getName(){
return this->name;
}
void showCourses(){
for(COURSE* course : listCourses)
std::cout << course->getName() << std::endl;
}
};
in COURSE.h
#include <iostream>
#include <vector>
// #include "STUDENT.h"
class STUDENT;
class COURSE {
string name;
std::vector<STUDENT*> listStudents;
public:
COURSE(){}
addStudent(STUDENT* &student){
listStudents.push_back(student);
student.addCourse(this);
}
string getName(){
return this->name;
}
void showStudent(){
for(STUDENT* student : listCourses)
std::cout << student->getName() << std::endl;
}
};
If I include two classes each other, it said errors. If I just include one, just one class worked, other class has problem.
Can anyone help me to fix it and I wonder that is it necessary to use some design patterns or data structures to solve this.
Thank you
Yes, what you are attempting is possible, but not in the way you are attempting it. You need to separate your method declarations and definitions.
Also, you have a flaw in your add... methods that will lead to endless recursion as soon as a Student is added to a Course or vice versa. You need to detect when the two are already linked together so that you can avoid the loop.
Try something more like this:
Student.h
#ifndef StudentH
#define StudentH
#include <vector>
#include <string>
class Course;
class Student {
std::string name;
std::vector<Course*> listCourses;
public:
Student() = default;
~Student();
std::string getName() const;
void addCourse(Course* course);
void removeCourse(Course* course);
void showCourses() const;
};
#endif
Student.cpp
#include "Student.h"
#include "Course.h"
#include <iostream>
#include <algorithm>
Student::~Student() {
for(Course* course : listCourses) {
course->removeStudent(this);
}
}
std::string Student::getName() const {
return name;
}
void Student::addCourse(Course* course) {
if (std::find(listCourses.begin(), listCourses.end(), course) == listCourses.end()) {
listCourses.push_back(course);
course->addStudent(this);
}
}
void Student::removeCourse(Course* course) {
auto iter = std::find(listCourses.begin(), listCourses.end(), course);
if (iter != listCourses.end()) {
listCourses.erase(iter);
course->removeStudent(this);
}
}
void Student::showCourses() const {
for(Course* course : listCourses) {
std::cout << course->getName() << std::endl;
}
}
Course.h
#ifndef CourseH
#define CourseH
#include <vector>
#include <string>
class Student;
class Course {
std::string name;
std::vector<Student*> listStudents;
public:
Course() = default;
~Course();
std::string getName() const;
void addStudent(Student* student);
void removeStudent(Student* student);
void showStudents() const;
};
#endif
Course.cpp
#include "Course.h"
#include "Student.h"
#include <iostream>
#include <algorithm>
Course::~Course() {
for(Student* student : listStudents) {
student->removeCourse(this);
}
}
std::string Course::getName() const {
return name;
}
void Course::addStudent(Student* student) {
if (std::find(listStudents.begin(), listStudents.end(), student) == listStudents.end()) {
listStudents.push_back(student);
student->addCourse(this);
}
}
void Course::removeStudent(Student* student) {
auto iter = std::find(listStudents.begin(), listStudents.end(), student);
if (iter != listStudents.end()) {
listStudents.erase(iter);
student->removeCourse(this);
}
}
void Course::showStudents() const {
for(Student* student : listStudents) {
std::cout << student->getName() << std::endl;
}
}

"<<" Operator overloading error when defined outside main file

I tried to overload the << operator and wanted to use it in the main function. However, I get the following compiler error:
main.cpp:14:19: error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘const Point’)
std::cout << point;
~~~~~~~~~~^~~~~~~~
Interestingly, if I put all the code into a single file, it works just fine.
The code looks as follows:
main.cpp
#include <vector>
#include <iostream>
#include "data.hpp"
int main() {
const unsigned int n_points = 10;
Data data (n_points);
std::vector<Point> d;
d = data.get();
for (const auto& point : d){
std::cout << point;
}
return 0;
}
data.cpp
#include <cmath>
#include <algorithm>
#include "data.hpp"
Data::Data (unsigned int _n_samples) {
n_samples = _n_samples;
data.resize(n_samples, {4.0, 2.0});
}
std::vector<Point> Data::get(){
return data;
}
std::ostream& operator<<(std::ostream& out, const Point& point){
out << point.x << " " << point.y << '\n';
return out;
}
data.hpp
#ifndef DATA_H
#define DATA_H
#include <ostream>
#include <vector>
struct Point {
double x;
double y;
};
class Data {
public:
Data (unsigned int);
unsigned int n_samples;
std::vector<Point> get();
friend std::ostream& operator<<(std::ostream& out, const Point& point);
private:
std::vector<Point> data;
};
#endif /* DATA_H */
Can someone please tell me why this error occurs?
main() has no idea about your operator<< because you did not declare it in data.hpp in a scope where main() can find it. It needs to be declared as a free-floating function, not as a friend of the Data class, eg:
#ifndef DATA_H
#define DATA_H
#include <ostream>
#include <vector>
struct Point {
double x;
double y;
};
std::ostream& operator<<(std::ostream& out, const Point& point); // <-- moved here
class Data {
public:
Data (unsigned int);
unsigned int n_samples;
std::vector<Point> get();
private:
std::vector<Point> data;
};
#endif /* DATA_H */
It worked in one file because you put the definition of operator<< before main – if you move it to after main, you will encounter the same error.
The friend declaration does not add the declaration of the operator to the global scope, and there is no point in making it a friend of Data.

Composition: Objects as Members of Classes

Im am writing a code using the concept of Composition: Objects as Members of Classes and this error appeared for me: [Error] no match to 'operator<<'. Any one can help me? The error started appearing when i tried to include the trabalhador.h and trabalhador.cpp files. If i try to compile the code without this two files it works but i need bouth because im trying to implement this concept by my own.
Here is the code:
//main
#include <iostream>
using std::cout;
#include "trabalhador.h"
int main()
{
cout << "INFORME OS DADOS SOLICITADOS: \n\n";
cout << "Nome do funcionario: ";
info i1;
cout << "CPF: ";
info i2;
trabalhador t(i1, i2);
return 0;
}
//trabalhador.h
#ifndef TRABALHADOR_H
#define TRABALHADOR_H
#include "info.h"
class trabalhador
{
public:
trabalhador (const info &, const info &);
void print () const;
private:
const info funcionarioNome;
const info funcionarioCPF;
};
#endif
//trabalhador.cpp
#include <iostream>
using std::cout;
#include "trabalhador.h"
#include "info.h"
trabalhador::trabalhador (const info &infoNome, const info &infoCPF)
:funcionarioNome (infoNome),
funcionarioCPF (infoCPF)
{
cout << "Dados do funcionario: ";
}
void trabalhador::print() const
{
cout << funcionarioNome << funcionarioCPF;
}
//info.h
#include <string>
using std::string;
#ifndef INFO_H
#define INFO_H
class info
{
public:
info (string = "");
void setInfoDado (string);
void setInfo ();
private:
string infoDado;
};
#endif
//info.cpp
#include <iostream>
using std::cout;
using std::cin;
#include <string>
using std::string;
using std::getline;
#include "info.h"
info::info (string info)
{
setInfoDado (info);
}
void info::setInfoDado (string info)
{
infoDado = info;
setInfo();
}
void info::setInfo ()
{
string nome;
getline (cin, nome);
infoDado = nome;
}
You need to provide an overloaded operator<< for your info class.
The requirement for this stems from the line
cout << funcionarioNome << funcionarioCPF;
It needs to know how to render the class using an ostream.
It's as simple as
class info
{
public:
// ...
friend std::ostream& operator<<(std::ostream& os, info const& inf)
{
os << inf.infoDado;
return os;
}
// ...
};
See the full code here.
//new constructor in trabalhador.cpp
trabalhador::trabalhador (const info &infoNome, const info &infoCPF)
:funcionarioNome (infoNome),
funcionarioCPF (infoCPF)
{
cout << "\nDados do funcionario: \n";
print();
}
//function created in trabalhador.cpp
void trabalhador::print() const
{
funcionarioNome.print();
funcionarioCPF.print();
}
//function created in info.h
void print () const;
//function created in info.cpp
void info::print () const
{
cout << infoDado << "\n";
}

error: no matching function for call to 'std::reference_wrapper<Medium>::reference_wrapper()

Book and Article are derived classes from Medium.
Why am I getting this error when trying to insert Medium / Book / Article in the bibliography?
error: no matching function for call to '**std::reference_wrapper<Medium>::reference_wrapper()**
main.cc
#include <iostream>
using namespace std;
#include "Bibliography.h"
#include "Medium.h"
#include "Book.h"
#include "Article.h"
int main()
{
Bibliography p(1);
Medium m1("PN","I","Pasol nah",2017);
p.insert(m1);
cout << p;
return 0;
}
Bibliography.h
#ifndef BIBLIOGRAPHY_H_
#define BIBLIOGRAPHY_H_
#include "Medium.h"
#include "Article.h"
#include "Book.h"
#include <iostream>
#include <functional>
#include <vector>
class Bibliography
{
private:
int m_Size;
std::vector<std::reference_wrapper<Medium>> v;
int index;
public:
Bibliography(int size);
void insert(Medium m);
friend std::ostream& operator<<(std::ostream& out, const Bibliography &b1);
};
#endif
Bibliography.cc
#include "Bibliography.h"
Bibliography::Bibliography(int size)
{
std::cout << "Bibliography created \n";
m_Size = size;
v.resize(m_Size);
index = 0;
}
void Bibliography::insert(Medium m)
{
v.push_back(m);
}
std::ostream& operator<<(std::ostream& out, const Bibliography &b1)
{
for (Medium &Medium : b1.v)
{
out << Medium.toString() << std::endl;
}
return out;
}
You should not use reference_wrapper in vector, because vector is restricted when using it with classes that do not have a default constructor. reference_wrapper doesn't have it, look at these constructors of reference_wrapper:
// initialization (1)
reference_wrapper (type& ref) noexcept;
reference_wrapper (type&&) = delete;
// copy (2)
reference_wrapper (const reference_wrapper& x) noexcept;
In this line
v.resize(m_Size);
you want to create m_Size reference_wrapperobjects, but the default constructor for reference_wrapper doesn't exist, and code cannot be compiled.
You can use reference_wrapper with vector but you will get a compilation error
when a method of vector is called, that needs the default constructor to be defined.

Error with const member in class

I have a class named Student with its Name and Address classes.
#ifndef ADDRESS_H
#define ADDRESS_H
//This is address class
#include <string>
class Address{
public:
Address(std::string street, std::string city, std::string state, std::string zip) :
street(street), city(city),state(state),zip(zip)
{}
std::string street,city,state,zip;
std::string aString;
aString=street+city+state+zip;
//private:
};
#endif
and the Name class is
#ifndef NAME_H
#define NAME_H
#include <iostream>
#include <string>
class Name {
friend std::ostream &operator <<(std::ostream &os, const Name &name) {
if(name.middle!="")
os << name.last << ", "<<name.middle<<" ," << name.first;
else
os<< name.last <<", "<<name.first;
return os;
}
public:
Name(std::string last, std::string middle, std::string first) : last(last), first(first),middle(middle) {}
private:
std::string last, first, middle;
};
#endif
And the Student class is like:
#ifndef PERSON_H
#define PERSON_H
#include <iostream>
#include <string>
#include "name.h"
#include "Address.h"
class Person {
friend std::ostream &operator <<(std::ostream &os, const Person &person);
public:
Person(const Name &name, int age, const Address &address);
Address address;
std::string adr=address.aString;
//private:
Name name;
int age;
};
#endif
Finally, to call them.
#include <iostream>
#include "student.h"
#include <string>
using namespace std;
Person::Person(const Name &name, int age, const Address &address) : name(name), age(age),address(address) {}
ostream &operator <<(ostream &os, const Person &person) {
os << person.name << " " << person.age<<person.adr;
return os;
}
#include <iostream>
#include "student.h"
using namespace std;
int main() {
Person p(Name("Doe","","Jane"), 21, Address("Park Ave","New York","NY","10002"));
Person p2(Name("Bane","IHateM","Jane"), 21, Address("Bay parkway","Brooklyn","NY","11223"));
cout << p<<endl;
cout<< p2<<endl;
return 0;
}
However, there are some errors during compilation.
(1) The following line is wrong based on complier, how to fix it please?
std::string adr=address.aString;
(2) In my address class, the compiler said that "string does not name a type Error", but following this Why am I getting string does not name a type Error? can't fix the problem, why is that?
Simple Solution
The simplest solution is to move your aString=street+city+state+zip; inside the Address constructor.
Do the same for your adr = ... statement (you'll still need a 'declaration' for std::string adr; within your class header).
To understand why what you wrote won't work, consider this:
When you write (within a class declaration, like in your header)
class myClass
{
int a = 5;
};
you assign a default value to the int a that you have declared - this is both declaration and (default) assignment.
When you write
class Address{
public:
Address(std::string street, std::string city, std::string state, std::string zip) :
street(street), city(city),state(state),zip(zip)
{}
std::string street,city,state,zip;
std::string aString;
aString=street+city+state+zip;
};
you're trying to give a default assignment to aString, but this is invalid code.
You could do this using
std::string aString = ...;
but not
std::string aString;
aString = ...;
because the last line is a 'statement' - something to be executed.