0

I don't know how I should handle passed objects pointer in my non-default constructor. I am doing this program wrong because I feel like I don't know what I'm doing.

I've been stuck on this for a day and a half and I just don't understand it. I will post majority of my homework where I must use default constructor and non default constructor. I will also include the class diagram that I'm using so you can see how variables/classes/methods function.

What should I be doing with passed pointers inside of non-default constructor? I can't assign any values through here because it will tell me that its inaccessible. In this piece of code:

Book::Book(string title, Author *pAuthor, Publisher *pPublisher, double price)
    {
        setTitle(title);
        setPrice(price);
    }

Any idea how to use those pointers? Right now I can correctly pass everything by using default constructor, but I'm probably doing this wrong since I am using additional objects. Basically I shouldn't have 2 lines with Author author; and Publisher publisher; but I don't care at this point.

Please help!

Book.cpp file

#include <iostream>
#include <sstream>
using namespace std;

#include "Book.h"
#include "Publisher.h"
#include "Author.h"

class Book
{
    public:
        Book();
        Book(string title, Author *pAuthor, Publisher *pPublisher, double price);
        ~Book();
        void setTitle(string title);
        void setAuthorName(string first, string last);
        void setPublisher(string name, string address, string city);
        void setPrice(double price);
        string convertDoubleToString(double number);
        string getBookInfo();

    private:
        string title;
        double price;
        Author *pAuthor;
        Publisher *pPublisher;

    Author author;
    Publisher publisher;
};

Book::Book()
{
}

Book::Book(string title, Author *pAuthor, Publisher *pPublisher, double price)
{
    setTitle(title);
    setPrice(price);
}

Book::~Book()
{
}

void Book::setTitle(string  title)
{
    this->title = title;
}

void Book::setAuthorName(string first, string last)
{
    author.setFirstName(first);
    author.setLastName(last);
}

void Book::setPublisher(string name, string address, string city)
{
    publisher.setName(name);
    publisher.setAddress(address);
    publisher.setCity(city);
}

void Book::setPrice(double price)
{
    this->price = price;
}

string Book::convertDoubleToString(double number)
{
    return static_cast<ostringstream*>( &(ostringstream() << number) ) -> str();
}

string Book::getBookInfo()
{
    return title + "\n" + author.getFullName() + "\n" + publisher.getPublisherInfo() + "\n" + "$" + convertDoubleToString(price);
}

Main.cpp file:

#include <iostream>
#include <string>
using namespace std;

#include "Book.h"

int main()
{
    system("cls");

    cout << "Book 1" << endl;

    Author *pAuthor = new Author("John", "Doe");
    Publisher *pPublisher = new Publisher("Wrox", "10475 Crosspoint Blvd.", "Indianapolis");
    Book *pBook = new Book("Memory Management", pAuthor, pPublisher, 39.99);

    cout << pBook->getBookInfo() << endl;

    cout << endl << "Book 2" << endl;

    Book book;

    book.setTitle("Advanced C++ Programming");
    book.setAuthorName("Linda", "Smith");
    book.setPublisher("Microsoft Press", "One Microsoft Way", "Redmond");
    book.setPrice(49.99);

    cout << book.getBookInfo() << endl << endl;

    system("pause");

    return 0;
};

Author.cpp file:

#include <iostream>
#include <string>
using namespace std;

class Author
{
    public:
        Author();
        Author(string first, string last);
        string getFullName();
        void setFirstName(string first);
        void setLastName(string last);

    private:
        string firstName;
        string lastName;
};

Author::Author()
{
}

Author::Author(string first, string last)
{
    setFirstName(first);
    setLastName(last);
}

string Author::getFullName()
{
    return firstName + " " + lastName;
}

void Author::setFirstName(string first)
{
    this->firstName = first;
}

void Author::setLastName(string last)
{
    this->lastName = last;
}

Class Diagram:

enter image description here

Mat
  • 202,337
  • 40
  • 393
  • 406
HelpNeeder
  • 6,383
  • 24
  • 91
  • 155
  • 2
    You really don't want to give two different things the same name. Your function has a parameter called `pAuthor` but you also have a class member with that same name. That's going to cause you no end of problems. – David Schwartz Sep 04 '12 at 05:03
  • I have a feeling your code does not even compile because you are passing pointers to functions that do not take pointers as arguments - if you add your compile errors people will tell you whats up – Adrian Cornish Sep 04 '12 at 05:14
  • @Adrian Cornish, it compiles and runs. I just did little modification to add headers to the *cpp files. It displays data fine with default constructor. The problem is that when I run the fields with title publisher and author information in non-default constructor are blank spaces. – HelpNeeder Sep 04 '12 at 05:16

3 Answers3

1

You need to allocate enough memory to your pointer members to hold the data being passed through the pointers and then copy the data pointed by the passed pointer to your member pointer variables.

In short you need to perform a Deep Copy of the passed pointer members. So that your pointer members own the data to which they point.

EDIT:
Though the soultion you posted might seem to work, it still has problems:

Book::Book() 
{     
    pAuthor = new Author();     
    pPublisher = new Publisher(); 
} 

Dynamically allocates memory to the class pointer members, they indeed need their own memory allocation because your class should own and control the lifetime of these members.
You might want to have a look at Member Initializer Lists. However, the patameterized constructor of Book class which takes 4 parameters still does not allocate any memory. It still performs a shallow copy of pointers passed to it.

What is a shallow copy?

Shallow copy is nothing but simply pointing a pointer to some address.It means your pointer is not solely in control of the pointed object.If some other pointer which points to the same object deallocates the object(by calling `delete etc), then what you ar eleft with is a pointer pointing to something that does not exist anymore, a.k.a a dangling pointer.

This is what happens when you do:

Book::Book(string title, Author* pAuthor, Publisher* pPublisher, double price) 
{
    ....
    this->pPublisher = pPublisher;           
    this->pAuthor = pAuthor;     
    ....
}

What you need to avoid this situation is Deep Copy.

What is a Deep copy?

Deep Copy means, allocating your pointer a separate memory and then copying the contents of another pointer to memory of your own object(unlike in shallow copy).This separates the lifetime of the object pointed by your pointer separate from the lifetime of the pointer from which it was created.

For this to happen you should allocate separate memory to your pointer members and then the overloaded = operators of your classes Author and Publisher should copy each member of the respective classes. Have a look at copy and swap idiom for how to implement this correctly in C++.

Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • Would you mind giving me some code on this? I don't know about c++ much. – HelpNeeder Sep 04 '12 at 05:06
  • 1
    @HelpNeeder: Can you try on your own and post precise problem you face.This is homework and that is precisely the reason I gave you hint and not the code. – Alok Save Sep 04 '12 at 05:08
  • @Als The OP is allocating memory for the pointers, I see a few `new`s havent checked them all - their problem seems to be not understanding what a pointer is and passing it to a func that takes class and not a pointer to a class. – Adrian Cornish Sep 04 '12 at 05:09
  • 1
    @AdrianCornish: I don't see any of the pointer members being allocated any memory. – Alok Save Sep 04 '12 at 05:44
  • @Als Ah now I see - I really was not reading the OP's code I saw the `Author *pAuthor = new Author("John", "Doe");` but did not even look at class members which I see now are pointers – Adrian Cornish Sep 04 '12 at 07:36
  • I just posted code as an answer which was exactly what I needed to do. I still don't understand about that deep copy. Is my answer relevant to your answer? – HelpNeeder Sep 06 '12 at 01:01
  • 1
    @HelpNeeder: I updated the answer to explain in detail.Hope that helps. – Alok Save Sep 06 '12 at 04:57
  • 1
    I didn't understand at first, but your answer was correct. I just didn't know how to apply it -_-. Thank you. – HelpNeeder Sep 06 '12 at 07:49
1

Unless the assignment requires that you use pointer data members, the best solution is to simply remove them altogether, and modify the relevant constructor, which you can also improve by using an initialization list:

class Book {

  ....
 public:
  Book(std::string title, const Author& author, const Publisher& publisher, double price);
 private:
  // use some convention for private data member names, here trailing _
  std::string title_;
  double price_;
  Author author_;
  Publisher publisher_;

};

Book::Book(string title, const Author& author, const Publisher& publisher, double price)
 : title_(title), price_(price), author_(author), publisher_(publisher) 
{

}

Edit: since it seems to be a requirement to use pointers, and since the Book class has methods that attempt to modify the Author and Publisher, you need to make a deep copy of the object pointed to by the input pointers. This means dynamically allocating an object with new and assigning a pointer to it to one of your pointer data members. For example,

class A { .... }; // class with copy constructor

A* a1; // pointer to an A, points to nothing.
a = new A(); // a1 now points to dynamically allocated A. You are in charge of deleting!
A* a2(new A); // pointer to an A, initialized to point to dynamically allocated A.

But then you are in charge of deleting the dynamically allocated objects, and must modify your class to make copy constructing and assigning sensible, i.e. follow the rule of three. Hopefully you will see that using pointers in this particular case causes more problems than its worth.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • `*pAuthor` and `*pPublisher` instead of `author` and `publisher`, I guess. – Gorpik Sep 04 '12 at 06:15
  • 1
    @Gorpik Not really, but almost. I fixed the typos. – juanchopanza Sep 04 '12 at 06:20
  • Sory for late reply. But why are you using `&` instead of `*`? – HelpNeeder Sep 04 '12 at 16:09
  • @HelpNeeder the point I am trying to make is that more often than not, you are better off without pointers. So, unless it is a requirement of your assignment, I suggest taking the objects by const reference and using those to initialize your own objects. – juanchopanza Sep 04 '12 at 22:01
  • Yes, I must use pointers for this assignment. I'm just so confused about this that I don't know how to implement this into my code. – HelpNeeder Sep 05 '12 at 00:16
  • @HelpNeeder OK, since you have functions in `Book` that can modify its `Author` and `Publisher`, it looks like you need your own copies of the objects pointed to. See Als' answer. I will add some links to mine. – juanchopanza Sep 05 '12 at 05:27
  • Thank you for trying to explain to me about pointers. I have added my answer to show what I was exactly looking for :) – HelpNeeder Sep 06 '12 at 01:00
  • 1
    @HelpNeeder OK, but there are still some problems with your code. Think of what would happen if you copied `pBook`, and have another look at the *rule of three* link I posted in my answer. – juanchopanza Sep 06 '12 at 05:44
1

After few minutes talking to my classmate I figured out that I was missing few vital lines of code.

I guess the problem with my question was that I don't understand pointers how I should have. After few tips from professor and classmates I knew that I was missing few lines of code within default and non-default constructor.

Here I will show what I was exactly looking for:

Main.cpp file:

#include <iostream>
#include <string>
using namespace std;

#include "Book.h"

int main()
{
    system("cls");

    cout << "Book 1" << endl;

    Author *pAuthor = new Author("John", "Doe");
    Publisher *pPublisher = new Publisher("Wrox", "10475 Crosspoint Blvd.", "Indianapolis");
    Book *pBook = new Book("Memory Management", pAuthor, pPublisher, 39.99);

    cout << pBook->getBookInfo() << endl;

    cout << endl << "Book 2" << endl;

    Book *book = new Book();

    book->setTitle("Advanced C++ Programming");
    book->setAuthorName("Linda", "Smith");
    book->setPublisher("Microsoft Press", "One Microsoft Way", "Redmond");
    book->setPrice(49.99);

    cout << book->getBookInfo() << endl << endl;

    system("pause");

    return 0;
};

Book.cpp file:

#include <iostream>
#include <sstream>
using namespace std;

#include "Book.h"

Book::Book()
{
    pAuthor = new Author();
    pPublisher = new Publisher();
}

Book::Book(string title, Author* pAuthor, Publisher* pPublisher, double price)
{
    this->title = title;
    this->price = price;

    this->pPublisher = pPublisher;
    this->pAuthor = pAuthor;
}

Book::~Book()
{
    delete pAuthor;
    delete pPublisher;
}

void Book::setTitle(string  title)
{
    this->title = title;
}

void Book::setAuthorName(string first, string last)
{
    pAuthor->setFirstName(first);
    pAuthor->setLastName(last);
}

void Book::setPublisher(string name, string address, string city)
{
    pPublisher->setName(name);
    pPublisher->setAddress(address);
    pPublisher->setCity(city);
}

void Book::setPrice(double price)
{
    this->price = price;
}

string Book::convertDoubleToString(double number)
{
    return static_cast<ostringstream*>( &(ostringstream() << number) ) -> str();
}

string Book::getBookInfo()
{
    return title + "\n" + pAuthor->getFullName() + "\n" + pPublisher->getPublisherInfo() + "\n" + "$" + convertDoubleToString(price);
}
HelpNeeder
  • 6,383
  • 24
  • 91
  • 155