I'm fairly noobish at C++, but very comfortable with pointers, dereferencing, etc. I'm having a problem with my overload of the << operator for a class, in that it compiles fine but crashes when run. It feels like an infinite loop, but I'm not certain. Here's the code, and any help is appreciated.
#include <string>
#include <iostream>
using namespace std;
class Person
{
private:
string _name;
Person* _manager;
public:
Person(string name, Person *manager);
Person(string name);
friend ostream &operator<<(ostream &stream, Person &p);
};
Person::Person(string name, Person *manager)
{
_name = name;
_manager = manager;
}
Person::Person(string name)
{
_name = name;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
stream << mgr->_name << std::endl;
return stream;
}
int main()
{
Person *pEmployee = new Person("John Doe Employee");
Person *pManager = new Person("John Doe Manager", pEmployee);
cout << *pEmployee;
cout << *pManager;
return 0;
}
In your constructor with just a single argument, you need to set _manager to NULL/0. Test for this in your operator<< and don't output mgr->name if it is NULL/0. As it stands, you are dereferencing an uninitialised pointer.
Person::Person(string name)
{
_name = name;
_manager = 0;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
if (mgr)
stream << mgr->_name << std::endl;
return stream;
}
There are a number of other things you could do better, such as using const references on arguments and using the constructor initialiser list, but they wont be the cause of your problem. You should also address ownership issues with the manager object you pass in to the constructor to ensure it does not get double-deleted.
your _manager pointer is not initialized upon constructing the first Person instance, hence referencing p._manager in your operator << crashes.
Besides that, you have a memory leak since you call new but not delete.
Your implementation of operator<< does not check if the _manager member is valid. If there is no manager, you should make this explicit by setting the pointer to 0. Otherwise the pointer value is undefined and accessing it will crash your program.
(1) Your Person class should set _manager to 0 (null pointer) if none is supplied in the constructor:
Person::Person(string name) : _name(name), _manager(0)
{
}
(2) In your operator<<, check the pointer before dereferencing it:
if (mgr) {
stream << mgr->_name << std::endl;
}
Some hints for better code:
(1) Change your function arguments to accept const string& instead of string. This way, the string is not copied when calling the function/constructor, but passed as a constant reference.
(2) It is cleaner to let your operator<< accept a const reference for the Person as well, since it does not/should not modify the Person. This way, you can use the operator also in places where you have a constant Person.
Person::Person(string name)
{
_name = name;
}
Who is your manager?
Person::Person(string name) : _manager(NULL)
{
_name = name;
}
ostream &operator<<(ostream &stream, Person &p)
{
Person* mgr = p._manager;
stream << p._name << std::endl;
if (mgr != NULL) { stream << mgr->_name << std::endl; }
return stream;
}
Your Person instance *pEmployee does not have the _manager set. This may be a NULL pointer.
Related
https://leetcode.com/explore/learn/card/fun-with-arrays/521/introduction/3294/
I'm following this Leetcode course on Arrays and am trying to follow along using C++ as they use Java, but I'm struggling to get past this part. I just want to read items from the pokedex array I made.
The initial error I got was:
No operator << matches these operands.
Array.cpp(16,15) operand types are std::ostream << Pokemon
I then tried to overload the << operator as I've seen other people ask on here, but I'm not getting the output I want. When I compile the program as-is, nothing prints.
Can someone explain what I can do to get the desired output?
Cyndaquill is a fire type at level 5
Also, can someone explain, or point me in the direction of someone who can explain, operator overloading in an easy non-verbose way? A lot of what I've seen on StackOverflow has been overly verbose and confusing. Maybe it's because I'm new to C++, but still.
Array.cpp
#include <iostream>
#include "Array_Header.hpp"
int main() {
Pokemon pokeDex[15];
Pokemon Cyndaquill = Pokemon("Cyndaquill", 5, "Fire");
Pokemon Totodile = Pokemon("Totodile", 5, "Water");
Pokemon Chikorita = Pokemon("Chikorita", 5, "Grass");
pokeDex[0] = Cyndaquill;
pokeDex[1] = Totodile;
pokeDex[2] = Chikorita;
std::cout << pokeDex[0];
std::cout << pokeDex[1];
std::cout << pokeDex[2];
std::cout << pokeDex[3];
}
Array_Header.hpp
#include <string>
class Pokemon {
public:
//variable declarations
std::string name;
int level;
std::string type;
//Constructor for the DVD class
Pokemon(std::string name, int level, std::string type);
Pokemon() = default;
//toString function declaration
std::string toString();
friend std::ostream& operator<<(std::ostream& os, const Pokemon& obj)
{
return os;
};
};
Array_Header.cpp
#include "Array_Header.hpp"
//Constructor Definition
Pokemon::Pokemon(std::string name, int level, std::string type){
this->type = type;
this->level = level;
this->name = name;
};
//toString function definition
std::string Pokemon::toString(){
return this->name + " is a " + this->type + " type at level " + std::to_string(level) + "\n";
};
Your operator overload for << to print to an std::ostream an object of type Pokemon does nothing but return the os parameter. You need to add the logic for printing inside of here, which would look something like this:
friend std::ostream& operator<<(std::ostream& os, const Pokemon& obj)
{
os << obj.toString();
return os;
};
Can you take a look at my overladed operator for the package class in my code below. Is it possible to access private variables of the parent class in child class? What I did is I used member functions to write a overloaded operator for the package class but it says "Variable 't' is uninitialized when used here". Go to the end and you will see overladed operator.
#include <iostream>
using namespace std;
// Ticket Class
class Ticket
{
private:
int runTime;
string movieName;
public:
Ticket(int, string);
void setMovieName(string);
void setRunTime(int);
string getMovieName();
int getRunTime();
friend ostream &operator <<(ostream &stream, const Ticket&);
};
// Package Class
class Package : public Ticket
{
private:
string snackName;
public:
Package(int, string, string);
void setSnackName(string);
string getSnackName();
friend ostream &operator <<(ostream &stream, const Package&);
};
int main()
{
}
// Ticket Class empty constructor
Ticket::Ticket(int rnTime, string mvTime) : runTime(rnTime), movieName(mvTime){}
// Ticket Class setter
void Ticket::setMovieName(string mv)
{
movieName = mv;
}
// Ticket class setter
void Ticket::setRunTime(int rn)
{
runTime = rn;
}
// Ticket class getter
string Ticket::getMovieName()
{
return movieName;
}
// Ticket Class getter
int Ticket::getRunTime()
{
return runTime;
}
// Ticket class friend overloaded function
ostream &operator <<(ostream &stream, const Ticket &t)
{
stream << "Movie name: " << t.movieName << endl;
stream << "Run time: " << t.runTime << endl;
return stream;
}
// Child Class empty Constructor
Package::Package(int rnTime, string mvTime, string snTime) : Ticket(rnTime,mvTime), snackName(snTime){}
// Package Class setter
void Package::setSnackName(string sn)
{
snackName = sn;
}
// Package Class Getter
string Package::getSnackName()
{
return snackName;
}
// Package class friend overloaded function
ostream &operator <<(ostream &stream, const Package &p)
{
Ticket *t; // compilers says "Variable 't' is uninitialized when used here"
stream << "Movie: " << t->getMovieName() << endl;
stream << "Run time: " << t->getRunTime() << endl;
stream << "Snack name: " << p.snackName << endl;
return stream;
}
Make your get functions constant, like so:
string getMovieName() const; // <- Note the const specifier
int getRunTime() const; // <- Note it here as well...
Since these functions do nothing more than just return the values... So it is always advisable to do this with all get functions that do not modify the private variables...
And do the same in the definitions as well...
The binary operator<< can simply be defined as:
ostream &operator <<(ostream &stream, const Package &p)
{
stream << "Movie: " << p.getMovieName() << endl;
stream << "Run time: " << p.getRunTime() << endl;
stream << "Snack name: " << p.snackName << endl;
return stream;
}
Note: The reason this works is that the constant const Package &p is a const-qualified parameter... (One that does not allow any modifications inside itself but can be directly assigned from outside, hence the usage of reference operator), and only allows constant member functions (Functions that don't take part in modifying the class members...) to be called from itself... And since we have declared getMovieName() and getRunTime() to be constant functions... They are run correctly...
Note: You should consider visiting here to know more about the different ways how a value can be passed to a parameter of specific type...
You can use the operator<< function defined for the base class in the implementation of the derived class.
ostream &operator <<(ostream &stream, const Package &p)
{
Ticket const& t = p;
stream << t;
stream << "Snack name: " << p.snackName << endl;
return stream;
}
This reduces code duplication and avoids the private member access problem.
When you use public inheritance, all public and protected members of the base class become public and protected in the derived class. In your example, runTime and movieName is private so you can't access it from outside class.
Also, runTime and movieName is already private in Parent. Once declared private, a member always remains private to the base class regardless of the type of inheritance.
To access runTime and movieName change Parent to:
protected:
int runTime;
string movieName;
If you want to access the size member from a derived class, but not from outside the class, then you want protected.
And you should inherit Child by:
class Package : public Ticket
So I recently got back into programming, in prep for my last year of physics and i'm having some trouble with an example.
It says I need to add the specific Exhibit class shown in the code, and then implement the functions. Then it wants me to display this as the output;
Max says Eeeeep
Jack says Roar
Petals says Woof
{ Max Jack Batty Sheepy Hippopotamusesy Turkey }
{ Max Jack Batty Sheepy Hippopotamusesy Turkey }
By overloading the << operator.
I've had a go, but im just stuck I believe i'm also doing the add() function incorrectly, so if someone could provide me with some insight it would be much appreciated.
Code:
#include <iostream>
#include <string>
using namespace std;
//------------------------------------------------------------
class Animal
{
private:
string name;
string sound;
public:
Animal(const string& n = "", const string& s = "");
~ Animal();
string getName() const {return name;}
string makeSound() const{return sound;}
};
Animal::Animal(const string&n, const string &s)
{
name=n;
sound=s;
}
Animal:: ~ Animal() //Destructor
{
}
ostream &operator <<(ostream& out, Animal & obj)
{
cout <<obj.getName()<<" says "<<obj.makeSound() ;
return out;
}
//------------------------------------------------------------
class Exhibit{
public:
Exhibit(int maxEnt = 10);
~Exhibit();
void add(const Animal& e);
Animal& operator [](size_t i){ return entries[i];};
friend ostream& operator <<(ostream& out, const Exhibit& obj);
private:
int MaxNumberOfAnimals;
int CurrentNumberOfAnimals;
Animal* entries;
};
Exhibit::Exhibit(int maxEnt)
{
MaxNumberOfAnimals=maxEnt;
}
Exhibit:: ~ Exhibit()
{
}
void add(const Animal& e)
{
int j=0;
entries[j]=e;
j++;
return;
}
ostream& operator <<(ostream& out, const Exhibit& obj)
{
cout <<"{ ";
for(int i=0;i++;i!=obj.MaxNumberOfAnimals)
{
cout << obj.entries[i] << ", ";
}
cout << "}"<<endl;
return out;
}
//------------------------------------------------------------
int main()
{
Animal* monkey = new Animal("Max", "Eeeeep");
Animal* tiger = new Animal("Jack", "Roar");
Animal* Dog = new Animal("Petals", "Woof");
cout << *monkey <<endl;
cout << *tiger <<endl;
cout << *Dog << endl;
Exhibit cage(10);
cage.add(*monkey);
cage.add(*tiger);
/*cage.add(Animal("Batty", "Screech"));
cage.add(Animal("Sheepy", "Bleat Bleat"));
cage.add(Animal("Hippopotamusesy", "growl"));
cage.add(Animal("Turkey","Gobble"));*/
cout << cage << endl;
cout << cage << endl;
delete monkey;
delete tiger;
delete Dog;
system("pause");
return 0;
}
//------------------------------------------------------------
One things that could be causing the problem with your << overloading is that you are sending everything to cout, rather than the out stream you pass in. A potential fix there could be changing "cout" to "out", as below:
ostream &operator <<(ostream& out, Animal & obj)
{
out <<obj.getName()<<" says "<<obj.makeSound() ;
return out;
}
As for your add function in your Exhibit class, it looks like you are initializing your counter 'j' each time you call the function, which means that it will always be 0. You can fix this by making your counter a private data member of the Exhibit class, or perhaps just by using your 'int CurrentNumberOfAnimals' to keep track, like below:
void add(const Animal& e)
{
entries[CurrentNumberOfAnimals]=e;
CurrentNumberOfAnimals++;
return;
}
There may be other errors in there that I didn't notice, but there are some.
Edit:
As posted in an above answer, entries is not initialized correctly. If you can, use a vector of Animals, like below:
#include <vector> //This should be in your Exhibit header file
class Exhibit{
public:
Exhibit(int maxEnt = 10);
~Exhibit();
void add(const Animal& e);
Animal& operator [](size_t i){ return entries[i];};
friend ostream& operator <<(ostream& out, const Exhibit& obj);
private:
int MaxNumberOfAnimals;
int CurrentNumberOfAnimals;
vector<Animal> entries;
};
This also simplifies your add function, though, see below:
void add(const Animal& e)
{
entries.push_back(e);
return;
}
2nd Edit:
So far as I can tell, this is how to do it using arrays. This is assuming that you need at most 10 animals in your "entries" array, since you have "int maxent = 10" in your original Exhibit class.
Your Exhibit class declaration could look like this (we shouldn't need the "int maxent" in your constructor anymore unless you need it for other reasons):
class Exhibit{
public:
Exhibit();
~Exhibit();
void add(const Animal& e);
Animal& operator [](size_t i){ return entries[i];};
friend ostream& operator <<(ostream& out, const Exhibit& obj);
private:
int MaxNumberOfAnimals;
int CurrentNumberOfAnimals;
Animal entries[10];
};
Your add function could then look like the first add function above, repasted here for convenience:
void add(const Animal& e)
{
entries[CurrentNumberOfAnimals]=e;
CurrentNumberOfAnimals++;
return;
}
entries[j] = e; - that's undefined behavior right there, because entries is uninitialized pointer (which results from junk data) and you're trying to access memory location which is pointed to by that invalid pointer.
If you can use std::vector, use it. Otherwise, your Exhibit class would need to partially implement one - allocation, deallocation, reallocation, deep copy if you want copyable Exhibit...
I'm learning c++ and found a problem that I dont understand. I have this simple code:
#include <iostream>
#include <vector>
class Person
{
string * name;
public:
Person(const string & n) : name {new string {n}} {}
~Person() {delete name;}
string getName() const {return *name;}
};
int main()
{
vector<Person> people;
people.push_back(Person("Tom"));
cout << "Name is: " << people.back().getName() << endl;
return 0;
}
When I run it, I have no output. Dont know why? However, when I do simillar, but without vector everything is ok:
int main()
{
Person tom {"Tom"};
cout << "Name is: " << tom.getName() << endl;
return 0;
}
As other said, better to do without pointers. However, if you wondering what is happening, the reason for what you get is that in this line people.push_back(Person("Tom")); Person object is created, and its copy passed to vector. However, once the object is copied, destructor is executed which deletes the string.
With your usage of pointers, both the original Person object and its copy point to the same string in memory. String gets deleted by destructor, and name pointer in the copy does not point to anything. Thus you get undefined behaviour.
To rectify this issue, either dont use pointers, or you need to define your own copy constructor. For example:
class Person
{
string * name;
public:
Person(const string & n) : name {new string {n}} {}
// copy constructor which makes new string in memory
//based on the original string.
Person(const Person & other) {
name = new string(other.getName());
}
~Person() { delete name; }
string getName() const {return *name;}
};
You are using wrong type. Your string is already a string type. Write the code like this.
class Person
{
public:
Person (const string& n) : name(n) { }
~Person() {}
string getName() const { return name; }
private:
string name;
};
If you insist to use pointer in your member variable, you shall overwrite the copy constructor and overload assign operator.
Give you an example:
class Person
{
public:
Person (const char* n) : name(new char[strlen(n)+1]) { strcpy(name, n); }
Person (const Person& p) : name(new char[strlen(p.name)+1]) { strcpy(name, p.name); }
~Person() { delete [] name; }
Person& operator=(const Person& p)
{
if ( &p == this ) return *this;
delete [] name;
name = new char[strlen(p.name)+1];
strcpy(name, p.name);
return *this;
}
string getName() const { return name; }
private:
char* name;
};
The reason why your code is buggy has already been explained, but if you have C++11, you can use emplace_back:
people.emplace_back("Tom");
Still, using pointers instead of a plain member variable is just unnecessarily complicating your program. The less memory management you have to do, the better. Read about the Rule of Zero. Better yet, if your getName() function doesn't do anything special, remove it and just make name public.
I know this question might be stupid, but i am new in C++ and i have a lot of problems with redefinitions of operands.
What i`m trying to do is to redefine the operand << to print my class "Person" information but it appears compiling error:
class Person {
private:
string name;
unsigned long personId;
string address;
public:
Person(string name2,unsigned long id,string adr) {
name = name2;
personId = id;
address = adr;
}
void operator<<(Person person) {
cout<<"Name: "<<person.name<<" Person ID: "<<person.personId<<" Person address: "<<person.address<<endl;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
Person person("Steven",1212121212,"USA");
cout<<person; //compiling error here
return 0;
}
What`s the right way to do this ?
operator << is binary operator, so, first parameter for it should be reference to std::ostream object in your case. Since your variables are private - you cannot overload operator << as free function. First parameter for class function is pointer to object of this class, so you should use friend specificator (which grants access to private variables of your class) on the function.
friend ostream& operator << (ostream& os, const Person& person)
{
os << "Name: "<< person.name << " Person ID: "
<< person.personId << " Person address: " << person.address << endl;
return os;
}
First of all the class definition shall be ended with a semicolon.
class Person {
// ...
};
Secondly you are speaking about overloading an operator not an operand.
Operator << is a binary operator that is applied to two operands. If you want to overload this operator for standard output stream and your class then you should specify as the first parameter standard output stream. Also it is much better to pass an object of your class by const reference. So the declaration will look as
std::ostream & operator <<( std::ostream &os, const Person &person );
That this operator could access data members of your class that are defined as private it should be declared as a friend function of the class or has access to public methods of the class that provide access to private data members.
For example
class Person {
private:
string name;
unsigned long personId;
string address;
friend std::ostream & operator <<( std::ostream &os, const Person &person );
public:
Person(string name2,unsigned long id,string adr) {
name = name2;
personId = id;
address = adr;
};
Or
class Person {
private:
string name;
unsigned long personId;
string address;
ostream & out( std::ostream &os ) const;
public:
Person(string name2,unsigned long id,string adr) {
name = name2;
personId = id;
address = adr;
};
and
std::ostream & operator <<( std::ostream &os, const Person &person )
{
return ( person.out( os ) );
}