Я не знаю, как я должен обрабатывать указатель переданных объектов в моем конструкторе не по умолчанию. Я делаю эту программу неправильно, потому что чувствую, что не знаю, что делаю.
Я застрял на этом полтора дня, и я просто не понимаю этого. Я опубликую большую часть своей домашней работы, где я должен использовать конструктор по умолчанию и не конструктор по умолчанию. Я также включу диаграмму классов, которую я использую, чтобы вы могли видеть, как функционируют переменные / классы / методы.
Что я должен делать с переданными указателями внутри конструктора не по умолчанию? Я не могу присвоить какие-либо значения здесь, потому что он скажет мне, что это недоступно. В этом куске кода:
Book::Book(string title, Author *pAuthor, Publisher *pPublisher, double price)
{
setTitle(title);
setPrice(price);
}
Есть идеи, как использовать эти указатели? Прямо сейчас я могу правильно передать все, используя конструктор по умолчанию, но, вероятно, я делаю это неправильно, так как использую дополнительные объекты. В принципе у меня не должно быть 2 строк с Author author;
а также Publisher publisher;
но мне все равно на этом этапе.
Пожалуйста помоги!
Файл Book.cpp
#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:
#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:
#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 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)
{
}
редактировать: поскольку кажется необходимым использовать указатели, а поскольку Book
класс имеет методы, которые пытаются изменить Author
а также Publisher
Вам необходимо сделать глубокую копию объекта, на который указывают указатели ввода. Это означает динамическое выделение объекта с new
и присвоение указателя на него одному из ваших членов данных указателя. Например,
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.
Но тогда вы отвечаете за deleting
динамически размещаемые объекты, и должны изменить ваш класс, чтобы сделать создание и присваивание копии разумными, то есть следовать правило трех. Надеюсь, вы увидите, что использование указателей в данном конкретном случае вызывает больше проблем, чем стоит.
После нескольких минут разговора с моим одноклассником я понял, что мне не хватает нескольких жизненно важных строк кода.
Думаю, проблема с моим вопросом заключалась в том, что я не понимаю указателей, как я должен иметь. После нескольких советов от профессора и одноклассников я понял, что мне не хватает нескольких строк кода в конструкторе по умолчанию и в конструкторе не по умолчанию.
Здесь я покажу, что именно искал:
main.cpp файл:
#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 файл:
#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);
}
Вам необходимо выделить достаточно памяти для элементов указателя, чтобы удерживать данные, передаваемые через указатели, а затем скопировать данные, указанные указателем, в переменные указателя элемента.
Короче нужно выполнить Deep Copy переданных членов указателя. Так что ваши указатели члены своя данные, на которые они указывают.
РЕДАКТИРОВАТЬ:
Может показаться, что опубликованная вами душа работает, но у нее все еще есть проблемы:
Book::Book()
{
pAuthor = new Author();
pPublisher = new Publisher();
}
Динамически распределяет память членам указателя класса, им действительно нужно выделение памяти, потому что ваш класс должен своя и контролировать продолжительность жизни из этих членов.
Возможно, вы захотите взглянуть на Списки инициализаторов.
Тем не менее, патаметризованный конструктор Book
Класс, который принимает 4 параметра, по-прежнему не выделяет никакой памяти. Он по-прежнему выполняет мелкая копия указателей, переданных ему.
Что такое мелкая копия?
Мелкая копия — это просто указатель на какой-то адрес. Это означает, что ваш указатель контролирует не только указанный объект. Если какой-либо другой указатель, который указывает на тот же объект, освобождает объект (вызывая `delete etc), то, что вы используете, это указатель на что-то, что больше не существует, a.k.a a свисающий указатель.
Вот что происходит, когда вы делаете:
Book::Book(string title, Author* pAuthor, Publisher* pPublisher, double price)
{
....
this->pPublisher = pPublisher;
this->pAuthor = pAuthor;
....
}
Что вам нужно, чтобы избежать этой ситуации Deep Copy.
Что такое Глубокая копия?
Deep Copy означает, что ваш указатель выделяется в отдельную память, а затем копируется содержимое другого указателя в память вашего собственного объекта (в отличие от мелкой копии). Это отделяет время жизни объекта, на который указывает указатель, отдельно от времени существования указателя, из которого он был создан.
Чтобы это произошло, вы должны выделить отдельную память вашим членам указателя, а затем перегружать =
операторы ваших классов Author
а также Publisher
следует скопировать каждого члена соответствующих классов. Посмотри на скопировать и поменять идиому для того, как правильно реализовать это в C ++.