Help with Pointers, pointers to objects, and classes - c++

I am looking to be pointed in the right direction.
I have 1 class Event
class Event{
private:
vector<string> Question;
char Mode;// 1 = Ascending 2 = Descending 3 = None
string EventName;
public:
Event(string Name){
EventName = Name;
SetQuestionSize();
SetQuestion();
Mode = 3;
}
void SetName(string NewName){
EventName = NewName;
}
void SetQuestionSize(){
Question.resize(15);
}
int ReturnQuestionSize(){
return Question.size();
}
void SetQuestion(){
Question[0]="Enter ";
Question[1]="1 ";
Question[2]="to ";
Question[3]="sort ";
Question[4]="in ";
Question[5]="ascending ";
Question[6]="order, ";
Question[7]="2 ";
Question[8]="for ";
Question[9]="Descending, ";
Question[10]="or ";
Question[11]="3 ";
Question[12]="to ";
Question[13]="ignore ";
Question[14]=EventName;
}
string ReturnQuestion(int Index){
return Question[Index];
}
/*vector<string> ReturnQuestion(){
return Question;
}*/
void SetMode(char NewMode){
if (NewMode == '0' || NewMode == '1' || NewMode == '2')
Mode = NewMode;
}
char ReturnMode(){
return Mode;
}
string ReturnName(){
return EventName;
}
};
This is will be a member of a second object, which will use Event's functions to store data in Event's members.
The problem I'm having is declaring an array of Event objects in my second object. When researching I came across ways to use an array of pointers to the first object, and some operator '->' that I'm guessing is related to virtual functions.
class WhatTheyWant{
Event *events[2];
public:
WhatTheyWant(){
events[0]= new Event("Miss");
events[1]= new Event("Dodge");
}
};
I'm very ignorant about pointers, and I know I will have to learn them eventually, but are they the best way to go or is there a better.

Since your Event class doesn't have a default constructor, you need to explicitly construct each object with its name, so the way you're doing it currently is the only way to do it.
If you add a default constructor to Event, you can do it in at least two other ways:
If you will always have a (small) fixed number of objects, you can just declare an array of constant size:
Event events[2];
Doing this will automatically construct the objects when WhatTheyWant is created, so you just need to set the names afterwards:
WhatTheyWant() {
events[0].SetName("Miss");
events[1].SetName("Dodge");
}
If you want to have a variable number of events, you can declare a single pointer and dynamically allocate an array of objects:
Event *events;
And you could probably give the number as a parameter to the constructor:
WhatTheyWant(int numEvents) {
events = new Event[numEvents];
for (int i = 0; i < numEvents; i++)
events[i]->SetName("...");
}
Also, not directly related to your question, but your Mode variable would be better modeled using an enumeration instead of a char. Using an enum makes it clearer as to what the variable really means, rather than using values like 0, 1 and 2. For example:
public:
enum ModeType { Ascending, Descending, None };
private:
ModeType Mode;
public:
Event() {
...
Mode = Ascending;
}
void SetMode(ModeType NewMode) {
Mode = NewMode;
}
ModeType ReturnMode() {
return Mode;
}

You can use either array of objects or array of pointers.
Array of objects go like below.
class WhatTheyWant{
Event events[2];
public:
WhatTheyWant()
{
events[0] = Event("Miss");
events[1] = Event("Dodge");
}
};
Note: You need to add default constructor to your event class to compile the above approach.
With the above approach, you do not need to take care of freeing Event objects. Whenever WhatTheyWant object gets destroyed, event objects get destroyed.
Array of pointers approach goes like you mentioned.
But you need to take care of freeing the memory allocated(Unless you use auto_ptr or some c++0x equivalent).
Deletion should happen in destructor like below.
class WhatTheyWant{
Event *events[2];
public:
WhatTheyWant(){
events[0]= new Event("Miss");
events[1]= new Event("Dodge");
}
~WhatTheyWant()
{
delete events[0];
delete events[1];
}
};

In C++, pointers are just like arrays
in your WhatTheyWant class, you define the private member:
Event *events[2];
This is an array of arrays (2D array) with variable length (of arrays) and 2 element in each array.
and the operator '->' is used when you want to access a (member of some kind of object) and that is called an object pointer (a pointer which points to an object) but when you define a normal object variable you use '.' operator.
If you've got the courage and knowledge to use them they are very useful but in general they're dangerous and that's why the new languages tend to go to the managed way.

Related

How to delete class as this and set it as null in c++

So, I have an array of a class called "Customer"
Customer** customersarray[] = new Customer*[customer];
I'm receiving int customer with cin.
anyways, in customer.cpp, there is a method called void deactivate().
which goes like this:
void Custmoer::deactivate()
{
if (this != NULL)
remove this;
//this = NULL; I want to do this but it doesn't work.
}
and the purpose of this is to remove it from customer array when satisfies a certain condition. So for example,
for (int i = customer - 1; i >= 0; i--)
{
if (customersarray[i]->getAngerLevel() == 5) {
customersarray[i]->deactivate();
}
for (int z = i; i < customer - 1; i++) {
*(customersarray + z) = *(customersarray + z + 1);
}
customer--;
}
so my first questions are:
why does this = NULL not work?
is there a simpler way to remove something from pointer array when a condition is satisfied? (for example, remove all customers that has anger level of 5.)
Your mistake is thinking that you can remove something from a Customer* array by some magic inside the Customer class, but that's not true. Just remove a customer from the customer array where ever the customer array is. For instance using remove_if
#include <algorithm>
Customer** customersarray = new Customer*[customer];
...
customer = std::remove_if(customersarray, customersarray + customer,
[](Customer* c) { return c->anger() == 5; }) - customersarray;
This updates the customer variable to be the new size of the array, but doesn't free or reallocate any memory. Since you are using dynamic arrays and pointers you are responsible for that.
Which is why you should really not be using pointers or arrays, but using vectors instead.
std::vector<Customer> customerVector;
Life will be so much simpler.
Type of "this" is a constant pointer which means you cant change where it points
Your function can return a boolean and if its true just set your pointer to null
You'll be much better off using a std::vector, all memory memory management gets much safer. You cannot modify the this pointer, but that would be meaningless anyway:
It is a local variable, so any other pointer outside would not be changed, not even the one you called the function on (x->f(): the value of x is copied into this).
It contains the address of the current object - the current object is at a specific memory location and cannot be moved away from (not to be mixed up with 'moving' in the context of move semantics!).
You can, however, delete the current object (but I don't say you should!!!):
class Customer
{
static std::vector<Customer*> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
delete this;
}
}
Might look strange, but is legal. But it is dangerous as well. You need to be absolutely sure that you do not use the this pointer or any other poiner to the current object any more afterwards (accessing non-static members, calling non-static functions, etc), it would be undefined behaviour!
x->commitSuicide();
x->someFunction(); // invalid, undefined behaviour!!! (x is not alive any more)
Similar scenario:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
{
customers.erase(i); // even now, this is deleted!!! (smart pointer!)
this->someFunction(); // UNDEFINED BEHAVIOUR!
}
}
}
If handling it correctly, it works, sure. Your scenario might allow a much safer pattern, though:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
Customer()
{
customers->push_back(this);
};
~Customer()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
}
}
There are numerous variations possible (some including smart pointers); which one is most appropriate depends on the use case, though...
First of all, attending to RAII idiom, you are trying to delete an object before using its destructor ~Customer(). You should try to improve the design of your Customer class through a smart use of constructor and destructor:
Customer() {// initialize resources}
~Customer() {// 'delete' resources previously created with 'new'}
void deactivate() {// other internal operations to be done before removing a customer}
Then, your constructor Customer() would initialize your internal class members and the destructor ~Customer() would release them if necessary, avoiding memory leaks.
The other question is, why do you not use another type of Standard Container as std::list<Customer>? It supports constant time removal of elements at any position:
std::list<Customer> customers
...
customers.remove_if([](Customer foo) { return foo.getAngerLevel() == 5; });
If you only expect to erase Customer instances once during the lifetime of the program the idea of using a std::vector<Customer> is also correct.

How to remove an item in a pointer vector belonging to a pointer object

I have a playlist class which contains a vector of song pointers.
class Playlist {
public:
Playlist();
Playlist(string);
vector<Song*> GetSongList() const;
private:
vector<Song*> songs;
string name;
};
The function GetSongList() is as follows:
vector<Song*> Playlist::GetSongList() const {
return songs;
}
In my main method I have a vector of playlist pointers: vector<Playlist*> playlists
I want to remove a song pointer from a specific playlist, but I'm having trouble. This is my current code to remove the indicated song:
Playlist* desiredPlaylist = playlists.at(index);
vector<Song*> temporarySongList = desiredPlaylist->GetSongList();
cout << "Pick a song index number to delete: ";
cin >> index;
temporarySongList.erase(tempSongList.begin() + index);
When I erase the song from the vector and re-output the contents of playlists.at(index).GetSongList() the song is not removed. I think the reason why is that calling GetSongList() does not retrieve the actual song vector, but just returns a copy, so I'm not altering the original vector. How do I directly remove the song from the original?
Use a member function remove_playlist to remove the song from the playlist. std::list (in place of vector) is recommended since frequent delete, move and insert is required within the playlist. Also use smart-pointer to avoid memory leaks like this std::list<std::shared_ptr<Song>>
void Playlist::remove_playlist(int index)
{
if( index < songs.size() )
{
auto v = songs.at(index);
songs.erase(std::remove(songs.begin(), songs.end(), v), songs.end());
}
}
You are right, the problem is caused by returning a copy.
You can either return a pointer
vector<Song*>* Playlist::GetSongList() {
return &songs;
}
or a reference
vector<Song*>& Playlist::GetSongList() {
return songs;
}
to your playlist.
A pointer is preferrable when it may happen, that there is no song list available and you thus sometimes have to return nullptr. So not in your example, because the member playlist is always available.
In most other cases, returning a reference is preferrable. Note that the method is not marked as const, because accesses to the returned vector<Song*>& alter the Playlist instance.
Another technique is to not return the member at all, but instead use a delegate to change the member.
void Playlist::ChangeSongList( const std::function<void(vector<Song*>&)>& fn ) {
fn(songs);
}
This has the benefit that the class which supplies the member can lock the access to the member in a threaded environment and is better informed when the member is changed (e.g. for debugging purposes - ChangeSongList could dump the contents before and after calling fn())
Anyway, returning a copy has often also performance problems and thus is often not preferrable. If you want to return a const member, you should use a const reference instead:
const vector<Song*>& Playlist::GetSongList() const {
return songs;
}
Please note that the answer seccpur gave is the most preferrable option in everyday life - a class should and usually takes care of its members itself, and don't let some outside code handle it. But this answer doesn't describe the difference in returning copies, pointers and references.
Quote
Playlist* desiredPlaylist = playlists.at(index);
vector<Song*> temporarySongList = desiredPlaylist->GetSongList();
cout << "Pick a song index number to delete: ";
cin >> index;
temporarySongList.erase(tempSongList.begin() + index);
You are creating a copy by doing this
vector<Song*> temporarySongList = desiredPlaylist->GetSongList();
So you are erasing from your local copy.
Consider changing
vector<Song*> GetSongList() const { return songs };
to
vector<Song*>& GetSongList() { return songs } ;

How do you place an Object inside a Room in a text-based game?

I'm a coding newbie (and despite what my user name may imply I am far from a pro), and I'm trying to write my own text-based adventure game. I have two questions.
First, I want to implement an Object class. These Objects have names and descriptions and can be placed in rooms, as well as picked up and carried around by the player. What's messing me up is that these Objects are supposed to know what room they were originally in, their "homeroom" so to speak.
I'm not sure how to let each Room know that they have Objects placed within them. Everything that I've tried to do has failed to compile.
I've tried to include Room r as a private variable in Object.cpp and include Room to the Object constructor.
Object::Object(string name, string description, Room *r)
{
name_ = name;
description_ = description;
r_ = r; //assume r_ is a private variable
}
Secondly, regarding pointers... This assignment specifies that I must have a vector of pointers of Objects. Would it look like this?
vector<Object*>objectsInRoom;
In main.cpp, I also need a vector of Objects. Is the vector inside the Room class keeping track of Objects in each Room? And is the vector in main.cpp keeping track of all the objects the player carries. Why must the room class have a vector of pointer of Objects? Would not having a vector of Objects suffice?
(I apologize if this sounds vague; this game is based off of an assignment that can be found here. If you scroll down to the "Extra Credit" portion and go to the first paragraph block marked 10 points, you'll find a much more extensive explanation that I tried to condense above.)
room.cpp
// Room.cpp: implementation of the Room class.
//
//////////////////////////////////////////////////////////////////////
#include "Room.h"
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
Room::Room()
{
name_ = "The void";
description_ = "There is nothing but blackness in every direction.";
int i;
for(i = 0; i < 4; i++) // set all exits to "closed"
exits_.push_back(NULL);
}
Room::Room(string name, string desc)
{
name_ = name;
description_ = desc;
int i;
for(i = 0; i < 4; i++) // set all exits to "closed"
exits_.push_back(NULL);
}
Room::~Room()
{
cout << "Destroying: " << name_ << endl;
// make sure all exits to this room are
// destroyed so that no one can try to enter
// this room from another location
if(exits_[NORTH] != NULL)
disconnect(NORTH);
if(exits_[EAST] != NULL)
disconnect(EAST);
if(exits_[SOUTH] != NULL)
disconnect(SOUTH);
if(exits_[WEST] != NULL)
disconnect(WEST);
}
// --- inspectors ---
Room * Room::north() const
{
return exits_[NORTH];
}
Room * Room::south() const
{
return exits_[SOUTH];
}
Room * Room::east() const
{
return exits_[EAST];
}
Room * Room::west() const
{
return exits_[WEST];
}
string Room::name() const
{
return name_;
}
string Room::description() const
{
return description_;
}
/*
vector<Object> Room::object() const
{
return roomObjects;
}
*/
// --- mutators ---
void Room::set_name(string n)
{
name_ = n;
}
void Room::set_description(string d)
{
description_ = d;
}
/*
void Room::set_object(Object o)
{
allObjects.push_back(o);
}
*/
// --- facilitators ---
bool Room::connect(Direction exit, Room *r, Direction to)
{
// check that both exits are free
if (exits_[exit] != NULL or r->exits_[to] != NULL)
return false;
// make connection
exits_[exit] = r;
r->exits_[to] = this;
return true;
}
// --- private methods ---
void Room::disconnect(Direction d)
{
// disconnects ALL exits from another
// room to this one. It's sloppy, but
// that's OK.
Room * other_room;
other_room = exits_[d];
int i;
for(i = 0; i < 4; i++) {
if (other_room->exits_[i] == this)
other_room->exits_[i] = NULL;
}
}
// --- operators ---
ostream & operator<<(ostream & out, const Room & r) {
out << r.name() << endl;
out << r.description() << endl;
return out;
}
Object.cpp
#include "Object.h";
Object::Object()
{
name_ = "Object";
description_ = "The object lies in the room";
}
Object::Object(string name, string description)
{
name_ = name;
description_ = description;
}
EDIT: So, If I simply add vector<Object*> allObjects under private attributes in Room.h, I get these enter image description here. Sorry, I'm not allowed to embed images yet.
I'd recommend (trying to adhere to your proposed architecture as much as possible) to define a method void Room::pushObject(Object* argObject). Inside your constructor Object::Object, you could add a call r->pushObject(this). Then you could iterate through your vector once you're inside a room.
Also, a linked list std::deque would be a better solution for your needs, as it is designed for faster insertion and deletion. Then you could room1.insert(room0.erase(yourObjPtr)) to move your objects around.
Note that the answer is theoretical, I did not check whether these compile or not.
Edit 1:
Why must the room class have a vector of pointer of Objects?
You might as well have a vector to the object instance itself, but when you wish to move the object to another room, program would have to copy all the content, instead of passing a single pointer. Also, it would prohibit the use of inheritance (you probably will get to use it in the near future :))
Edit 2:
I also see now that I misinterpreted your design. You intend to use a single global vector. I thought you wanted to use a more "object-oriented" approach, so to speak. I'd put a std::deque for each and every room, but if you wish to keep it this way, regarding your main question
I'm not sure how to let each Room know that they have Objects placed within them.
you might do something (thought inefficiently) like this:
void Room::processMyObjects(void)
{
for (int i = 0; i < globalObjectVector.size(); i++)
{
if (globalObjectVector[i]->r_ == myRoomId)
{
// do whatever you want here.
}
}
}
Also you'd either have to declare r_ public, write a public getter function, or declare friend class Room inside Object declarations this way, otherwise Room cannot see a private variable of Object.
You've got a Many-to-May relationship in this case. A room doesn't own the an object, an object is in a room. You can model Many-to-May relationship with a sparse map. Say, std::unordered_multimap<Room*, Object*>. With this approach you can easily query all objects in a particular room or move object to another room by associating in with different key. You will need a reverse map std::unordered_multimap<Object*, Room*> if you want to know which room contains your object. Also, smart pointers won't help you because you won't create and destroy objects often. It's better to bind objects' lifetime with lifetime of a level they're associated with.

Array Random Access C++

I'm probably going to confuse myself while writing this, sorry in advance:
Is there a way I can access a location in a dynamic array(increment an array pointer) of pointers using the sizeof() the object that is in the array?
For example:
I have an dynamic array of type base class Student populated with derived class objects(Graduate, Undergraduate).
Due to this I can't just step through my array in the normal fashion to display information because the actual objects Graduate and Undergraduate are different sizes than Student. Each array step will move sizeof(Student) when the actual objects are larger.
Depending on the type of student I am doing(this is for Graduate):
Student *student = new Graduate(undergrad, fName, lName, major, idNum, arr2, cSize,
degreeType, thesis);
arr[i] = student;
Where arr was declared: Student *arr = new Student[size];
Using my array I had created this in a for loop:
if (!students[i].getGradStatus()){
handleGraduate(&students[i], i);
step = step + sizeof(Graduate);
}
else if (students[i].getGradStatus()){
handleUndergraduate(&students[i], i);
step = step + sizeof(Undergraduate);
}
I was trying to come up with a way to change the step size. I don't think this will work with a for loop but a while loop may be different. Pretty much I'm trying to go something similar to a file seekg() but manually on an array.
And as I've noticed everyone likes to question the use of dynamic arrays over vectors so let me just say I cannot use vectors on this project(No STL is allowed :( ). And I have to use Polymorphism, thus why I have an array pointer of type Student holding derived class objects.
You can't store different sized objects in an array like that. When you try to copy a derived type like Graduate over a base type like Student you get what's known as slicing because of the differences in object size (parts can get chopped off).
To do this you need to store Student* (pointers to Students.)
class Student
{
std::string name;
public:
Student(const std::string& name): name(name) {}
virtual ~Student() {} // virtual destructor
virtual void handle() = 0; // implementation must override this
std::string get_name() const { return name; }
};
class Graduate
: public Student
{
public:
Graduate(const std::string& name): Student(name) {}
virtual void handle() { std::cout << "Handling Graduate" << '\n'; }
};
class UnderGraduate
: public Student
{
public:
UnderGraduate(const std::string& name): Student(name) {}
virtual void handle() { std::cout << "Handling UnderGraduate" << '\n'; }
};
int main()
{
Student** students = new Student*[3];
students[0] = new Graduate("Wendy");
students[1] = new UnderGraduate("Bob");
students[2] = new Graduate("Rachel");
for(int i = 0; i < 3; ++i)
{
std::cout << students[i]->get_name() << '\n';
students[i]->handle(); // polymorphic function (virtual)
}
delete[] students; // clean up or (better) use a smart pointer
}
Output:
Wendy
Handling Graduate
Bob
Handling UnderGraduate
Rachel
Handling Graduate
Change your array to be an array of Student pointers instead of Student objects.
Student **arr = new Student*[size];
When you do that your objects will live on the heap and the pointer size is always the same, so the issue you are having will go away.
Since you can write that I assume that it's possible to instantiate a Student (non-derived). That's bad, since you're going to store derived objects in the array your students will be sliced (poor students!). To counter that you're doing weird things with the size of the instance types. Just don't.
Make an array of student pointers instead, Student **arr. Pointers have fixed size and they will point to any of the derived types of student so you don't have to worry about their sizes.
Student **student = new Student*[size];
...
student[i] = new Graduate(...);
This should work.

Initializing a pointer array of objects

So I have the following code
class UserDB
{
private:
AccountInfo* _accounts[200] ; // store up to 200 accounts
public:
UserDB();
virtual ~UserDB();
}
UserDB::UserDB(){
//code for initializing it to null
}
UserDB::~UserDB(){
delete [] _accounts;
}
So basically I am trying to find this code to initialize _accounts to null but I cannot find a real answer, all the guides in the internet either say how to initialize an array, an object, or a pointer, but not something that is all three altogether, and even less how to initialize this kind of pointer to null, even whatever they are initializing [in the guides] looks very confusing, so I come once again to ask for help here.
Also, AccountInfo is just any random class.
use std::array or std::vector.
you don't delete[] _accounts because the array is a value -- it is an array of pointers. IOW, its size is not equal to a pointer.
Here's a std::vector approach:
class UserDB {
private:
std::vector<AccountInfo*> _accounts;
public:
UserDB() : _accounts(200, 0) {}
virtual ~UserDB() {}
};
However, you may prefer to use the vector's default initializer so you can use it to determine the number of accounts it holds.
Update in response to comments below:
Although there are reasons to hold an array of AccountInfo* pointers, you may also consider std::vector to hold an array of AccountInfos values:
class UserDB {
private:
std::vector<AccountInfo> _accounts;
public:
UserDB() : _accounts() {}
virtual ~UserDB() {}
void appendAccountInfo(const AccountInfo& info) {
this->_accounts.push_back(info);
}
};
std::vector will handle all your allocation and reallocation needs for you. It's also nice because it's dynamically resizable, and you won't be constrained to a fixed number of AccountInfos.
create a constant instead of the magic number 200 (not really necessary but it makes the code more readable and safer when later changing)
const int numberOfAccounts = 200;
AccountInfo* _accounts[numberOfAccounts]
UserDB::UserDB()
{
for (int i = 0; i < numberOfAccounts; ++i)
{
_accounts[i] = 0;
}
}
now you have you 200 zeroed pointers.
also have a habit of putting private members at the end of the class and public at the start,
especially by bigger classes you want to see the public stuff first, the private stuff you normally
don't want somebody to mess with.
class C
{
public:
protected:
private:
};
I do remember having read that this would work:
UserDB():_accounts(){}
This should initialize the contents to NULL