C++ output operator overloading - c++

I wanted to try to overload "<<" operator for an output stream and a custom class Article.
my.h
#include <iostream>
using namespace std;
class Article {
string body;
string header;
string author;
public:
Article();
void addHeader(const string&);
void addBody(const string&);
string getHeader();
string getBody();
};
my.cpp
string Article::getHeader() {
return header;
}
void Article::addBody(const string& body) {
this->body = body;
}
void Article::addHeader(const string& header) {
this->header = header;
}
ostream& operator<<(ostream& os, Article& article) {
return os << article.getHeader() << "\n\n" << article.getBody();
}
main.cpp
#include <iostream>
#include <string>
#include "my.h"
void main() {
char bye;
Article article = Article();
article.addBody("This is my article! thank you!");
article.addHeader("Header");
cout << article.getHeader() << "\n";
cout << article.getBody() << "\n";
cout << article;
cin >> bye;
}
This code doesn't compile. VS 2013 says:
binary '<<' : no operator found which takes a right-hand operand of type 'Article' (or there is no acceptable conversion)
If I remove the last line, it compiles successfully and the output of getHeader() and getBody() is as expected. They both return strings so it should be a piece of cake.
This problem seems very simple, however, as simple as it is I can't figure out what is happenning.

Now that you have posted real code the answer is obvious.
You define your operator << in my.cpp, but you don't declare it in my.h, so when compiling main.cpp the compiler has no way of knowing it exists.
Add a declaration of the function to your header.

Related

constructor does not work correctly while reading variables from txt file

I have a issue about my constructor is not correctly working. Whenever i run the program, my overloaded operator might not be perform correctly because i always get the default constructor values when i get the output with cout.
I believe that i made my constructor declarations well but all of my objects getting filled with 0 and Unknown
here is my txt file:
1 Prince Heins 25
2 Lady Bridgette 29
3 Tony Ann 223
4 Lucy Phoenix 35
Here is my code;
#include <iostream>
#include <string>
#include <conio.h>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#include <sstream>
#include <istream>
#include <iomanip>
#include <cstring>
#include <ostream>
using namespace std;
class contact{
private:
int listno;
string name;
string surname;
string phonenumber;
public:
contact(){
this->name="Unknown";
this->surname="Unknown";
this->phonenumber="Unknown";
this->listno=0;
}
contact (string name,string surname,string phonenumber){
this->name=name;
this->surname=surname;
this->phonenumber=phonenumber;
}
contact(int listno,string name,string surname,string phonenumber){
this->name=name;
this->surname=surname;
this->listno=listno;
this->phonenumber=phonenumber;
}
friend ostream & operator<< (ostream &out, const contact &con){
out << con.listno << con.name << con.surname << con.phonenumber;
return out;
}
friend istream & operator>> (istream &in, contact &con){
in >> con.listno >> con.name >> con.surname >> con.phonenumber;
return in;
}
};
int main(){
ifstream pbin("phoneData2.txt");
string line;
long linecount;
for(linecount=0;getline(pbin,line);linecount++);
contact* myArray = new contact[linecount];
pbin.seekg(0);
if(pbin.is_open()){
int i;
for(i=0;i<linecount;i++){
if(pbin!=NULL){
while(pbin>>myArray[i]);
}
}
pbin.close();
cout << myArray[2]; // try attempt
return 0;
}
}
and here is my output for cout << Array[2];
OutputArray2
The problem results from the wrong used algorithm and wrongly placed statements.
So, let's look what is going on in the below:
long linecount;
for(linecount=0;getline(pbin,line);linecount++)
;
contact* myArray = new contact[linecount];
pbin.seekg(0);
if(pbin.is_open()){
int i;
for(i=0;i<linecount;i++){
if(pbin!=NULL) {
while(pbin>>myArray[i]);
}
}
pbin.close();
You want to count the lines. So you read all lines until the eofstate is set. But, additionally, also the fail bit will be set. See also here.
If you use your debugger, you will find a 3 in _Mystate.
Then you perform a seekg. This will reset the eof bit but keep the fail bit. The dubugger shows then
You can see that the fail bit is still set.
So, and this will now lead to the main problem. If your write if(pbin!=NULL) which is definitely wrong (on my machine is does not even compile), or if you better write if(pbin) the fail bit will still be set. And because the bool and the ! operator for streams is overwritten (please see here) the result of the if and while will be false and your pbin>>myArray[i] will never be executed.
So, a pbin.clear() would help.
But, although your class definition is already very good, with inserter and extractor overwritten, you do not use the full C++ power for reading the data.
One basic recommendation would be to never use raw pointers for owned memory. And best also not new. Use dedicated containers for your purpose. E.g. a std::vector. The you can use the std::vectors constructor no 5 together with a std::istream_iterator. Please read here. The range based constructor for the std::vector will copy data from a given range, denoted by the begin and end iterator. And if you use the std::istream_iterator, it will call your overwritten extractor operator, until all data are read.
So your main shrinks to:
int main() {
// Open source file and check, if it could be opened
if (ifstream pbin("r:\\phoneData2.txt");pbin) {
// Read complete source file
std::vector data(std::istream_iterator<contact>(pbin), {});
// Show data on console
std::copy(data.begin(), data.end(), std::ostream_iterator<contact>(std::cout, "\n"));
}
return 0;
}
This looks by far compacter and is easier to read. We start with an if-statement with initializer. The initializer parts defines the variable and the constructor will open the file for us. In the condition part, we simple write pbin. And, as explained above, its bool operator will be called, to check if everything was ok.
Please note:
We do not need a close statement, because the destructor of the
std::ifstream will close the file for us.
The outer namespace will not be polluted with the variable name pbin. That is one of the reasons, why ifstatement with initializer should be used.
We alread descibed the std::vector with its range constructor. SO reading the complete file is simple done by the very simple statement
std::vector data(std::istream_iterator<contact>(pbin), {});
Please note:
We do not define the type of the std::vector. This will be automatically deduced by the compiler through CTAD
We use the default initialzer {} for the end iterator, as can be seen here in constructor number 1.
The whole program could then be rewritten to:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
class contact {
private:
int listno;
string name;
string surname;
string phonenumber;
public:
contact() {
this->name = "Unknown";
this->surname = "Unknown";
this->phonenumber = "Unknown";
this->listno = 0;
}
contact(string name, string surname, string phonenumber) {
this->name = name;
this->surname = surname;
this->phonenumber = phonenumber;
}
contact(int listno, string name, string surname, string phonenumber) {
this->name = name;
this->surname = surname;
this->listno = listno;
this->phonenumber = phonenumber;
}
friend ostream& operator<< (ostream& out, const contact& con) {
out << con.listno << '\t' << con.name << '\t' << con.surname << '\t' << con.phonenumber;
return out;
}
friend istream& operator>> (istream& in, contact& con) {
in >> con.listno >> con.name >> con.surname >> con.phonenumber;
return in;
}
};
int main() {
// Open source file and check, if it could be opened
if (ifstream pbin("r:\\phoneData2.txt");pbin) {
// Read complete source file
std::vector data(std::istream_iterator<contact>(pbin), {});
// Show data on console
std::copy(data.begin(), data.end(), std::ostream_iterator<contact>(std::cout, "\n"));
}
return 0;
}

Variable is not a type name error in c++

I already have another inventory that is working just fine, but for some reason, my Paperclip inventory is not working. Both inventories are nearly identical except for their names.
But this inventory keeps telling me: Error E0757 variable "Paperclip" is not a type name. For the lines where the errors are marked, I have bolded the word "Paperclip".
I am not exactly sure how to solve this. I have googled around and the name is not the same as my header file. My header file is Inventory_Paperclip.The error says its only in my header file.
If someone could help point me in the right direction, or give me some pointers of where I am going wrong, it would be appreciated. Please let me know if you would like to see my main or anything else.
I have posted my whole header file for Inventory_Paperclip below:
#ifndef Inventory_Paperclip
#define Inventory_Paperclip
#include <iostream>
#include <vector>
#include <string>
using namespace std;
//Base Class
struct Paperclip
{
const int itemID;
const char *name;
Paperclip(int i, const char *n) : itemID(i), name(n) {}
virtual const char *typeName() const
{
return "";
}
virtual void print(ostream &out) const
{
out << typeName() << "(" << itemID << ")" << name << endl;
}
}; // end of Base Class
typedef vector<Paperclip *> Paperclips;
ostream &operator<<(ostream &, const Paperclip &);
ostream &operator<<(ostream &, const Paperclips &);
//Only execute in a situation where the code is cout << Paperclip
ostream &operator<<(ostream &out, const Paperclip &paperclip)
{
paperclip.print(out);
return out;
}
//Only execute in a situation where the code is cout << Paperclips
ostream &operator<<(ostream &out, const Paperclips &paperclips)
{
for (Paperclips::const_iterator it = paperclips.begin(); it != paperclips.end(); it++)
{
out << **it << endl;
}
return out;
}
//function to print out my Paperclip
void printPaperclip()
{
Paperclips paperclips;
paperclips.push_back(new Paperclip(1, "-- Paperclip"));
cout << "Inventory Items: " << endl;
cout << paperclips << endl;
return;
}
#endif

Operators Not Working With Class Objects?

I'm trying to learn C++ and I'm creating small little programs to test out how it works. I made this code but for some reason I get this error on compiling:
binary '>>': no operator found which takes a left-hand operand of type 'std::istream' (or there is no acceptable conversion)
If anyone could help me figure this out I would appreciate it.
Code:
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <string>
#include "logo.h"
class classTest
{
public:
void setName(std::string x)
{
name = x;
}
std::string getName()
{
return name;
}
private:
std::string name;
};
int main()
{
SetConsoleTitle("plains.exe");
displayLogo();
std::cout << "Please enter your name: ";
classTest testObject;
std::cin >> testObject.setName;
std::cout << "Your name is " << testObject.getName() << "." << std::endl;
return 0;
}
setName is a function. So, you can not use cin >> testObject.setName. You can either do this-
string name;
cin >> name;
testObject.setName(name);
or use Operator Overloading to overload >>.
You are calling the instream operator on a void function
std::cin >> testObject.setName;
You need to first take the input in a string like and then call the setter to set the value
string inputName;
std::cin>>inputName;
testObject.setName(inputName);

Trying to convert a string into a int using stringstream

I'm trying check if a string representation equals given integer. I'm meant to use stringstream for this in a function. I also have an operator= for this as well.
I'm a little confused on how to execute these together and if I'm missing something. This is the last bit to an assignment I have, this is just a small snippet of my whole program. I can't find many guides on this, and I sense they all direct me to atoi or atod, which I'm not allowed to use.
#ifndef INTEGER
#define INTEGER
using std::string;
class Integer
{
private:
int intOne;
string strOne;
public:
Integer() {
intOne = 0;
}
Integer(int y) {
intOne = y;
}
Integer(string x) {
strOne = x;
}
void equals(string a);
Integer &operator=(const string*);
string toString();
};
#endif
In this header I'm not sure what argument I'm to use for the = operator.
#include <iostream>
#include <sstream>
#include <string>
#include "Integer.h"
using namespace std;
Integer &Integer::operator=(const string*)
{
this->equals(strOne);
return *this;
}
void Integer::equals(string a)
{
strOne = a;
toString(strOne);
}
string Integer::toString()
{
stringstream ss;
ss << intOne;
return ss.str();
}
#include <iostream>
#include <cstdlib>
#include <conio.h>
#include <string>
#include <ostream>
using namespace std;
#include "Menu.h"
#include "Integer.h"
#include "Double.h"
int main()
{
Integer i1;
i1.equals("33");
cout << i1;
}
Sorry if its a bad question I'm not too familiar with this type of assignment and will take any help I can get. Thanks.
you can use std::to_strig() that lets you convert from int to a string that represents the same number.
So if i understand correctly, you want to overload operator =, and that is a bad idea, since operator= is used for assignment not for comparison.
The correct operator signature is:
ReturnType operator==(const TypeOne first, const TypeSecond second) [const] // if outside of class
ReturnType operator==(const TypeSecond second) [const] // if inside class
Since you can't compare string to integer (they are different types), you need to write your comparisment function, since you don't have one i will write one for you:
bool is_int_equal_string(std::string str, int i)
{
std::string tmp;
tmp << i;
return tmp.str() == i;
}
Last but not least, you need to merge both of those, into one convenient operator:
// inside your Integer class
bool operator==(std::string value) const
{
std::stringstream tmp;
tmp << intOne;
return tmp.str() == ref;
}
Now you can use this operator, just like any other:
Integer foo = 31;
if (foo == "31")
cout << "Is equal" << endl;
else
cout << "Is NOT equal" << endl;
I hope this helps.
If you are allowed to use std::to_string then it would be the best.
Otherwise, you could create a function to handle the equality between the string and the integer with the use of std::stringstream:
Example:
bool Integer::equal(const string& str)
{
stringstream ss(str);
int str_to_int = 0;
ss >> str_to_int;
if (intOne == str_to_int)
return true;
else
return false;
}
Combine this with an if statement:
int main()
{
Integer i{100};
if (i.equal("100"))
cout << "true" << endl;
else
cout << "false" << endl;
}

C++ Passing vectors to an overloaded class - some call statements work, some do not.

I have spent a great deal of time in google trying to figure out how to pass a vector when using .h and .cpp files between a call in main and a function in an includes block. I was successful using class definitions.
Now everything is going fine until I want to create an overloaded function. (I could have done this with two different classes, but I must use one overloaded function in my program.)
Here is my writeData.h file:
#ifndef WRITEDATA_H
#define WRITEDATA_H
#include <vector>
#include <string>
#include <iostream>
#include <fstream>
using namespace std;
class writeData
{
public: writeData();
public: writeData(vector<int> & DATAFILE);
public: writeData(vector<int> & DATAFILE, string);
};
#endif
The placement of the using namespace std; is another topic.
Here is my writeData.cpp file:
#include "writeData.h"
writeData::writeData()
{
std::cout << "Default writeData" << std::endl;
}
writeData::writeData(vector<int> & DATAFILE)
{
cout << "writeData 1" << endl;
for (int var : DATAFILE)
{
cout << var <<endl;
}
}
writeData::writeData(vector<int> & DATAFILE, string fileName)
{
ofstream myfile(fileName);
cout << "writeData" << endl;
if (myfile.is_open())
{
for (int var : DATAFILE)
{
cout << var << endl;
myfile << var << endl;
}
myfile.close();
}
}
And here is my main function:
#include <iostream>
#include <vector>
#include <string>
#include "writeData.h"
using namespace std;
int main()
{
string fileName = "test.txt";
vector<int> items{ 10, 14, 22, 34 };
writeData();//default
///////////////////////////////////////////////////
// the next line is the problem code:
//writeData(items);//writes to screen only
//<<When I uncomment it the compiler Tosses the following:
// 'items': redefinition; different basic types
////////////////////////////////////////////////////
writeData(items, fileName);//writes to screen and to file
cin.ignore();
cin.get();
}
The offending line is writeData(items);
Any assistance or pointers to online articles would be most appreciated.
The immediate issue is that this declaration
writeData(items);
is the same as
writeData items;
hence the redefinition error. The deeper issue is that you have defined three constructors for a class, and seem to be attempting to call them without making a named instance. To succesfully call the one parameter constructor passing items, you'd need something like
writeData data_writer(items);
Alternatively, you may want either member functions, or non-members. The choice would depend on whether you really want to model a class, which maintains certain invariants or not. An example of members,
class writeData
{
public:
void write_data() const;
void write_data(const vector<int> & DATAFILE) const;
void write_data(const vector<int> & DATAFILE, string) const;
};
Then
WriteData wd;
wd.write_data(items);
Example of non-members:
namespace writeData
{
void write_data();
void write_data(const vector<int> & DATAFILE);
void write_data(const vector<int> & DATAFILE, string);
};
Then
writeData::write_data(items);
Note I have made the vector<int> parameters const reference because they are not being moified in the functions.