Назначение указателя C ++ в конструкторе пользовательских классов - PullRequest
0 голосов
/ 02 марта 2011

Итак, у меня есть собственный класс 'Book', в котором есть куча переменных-членов, среди которых есть вектор другого пользовательского класса с именем 'Review' и указатель на этот вектор, так как мне нужно передать его через функциюзвонки в программе драйвера.Программа драйвера считывает детали каждой книги (такие как название, автор, дата публикации и т. Д.) Из текстового файла и вставляет во временный объект «Книга», который затем добавляет в вектор книг, поддерживаемый программой драйвера.Вот код для чтения из файла:

ifstream file("books.txt");
string line;
if(file.is_open())
{
    while(!file.eof())
    {
        Book buffBook;
        getline(file, line);
        buffBook.setTitle(line);
        getline(file, line);
        buffBook.setAuthor(line);
        getline(file, line);
        buffBook.setPubDate(line);
        getline(file, line);
        buffBook.setIsbn(line);
        getline(file, line);
        buffBook.setCategory(line);
        getline(file, line);
        buffBook.setFormat(line);
        getline(file, line);
        buffBook.setSynopsis(line);
        vectBooks.push_back(buffBook);
    }
}

else
    cout<<"File not found(1)!"<<endl;

file.close();

Это выполняется внутри функции int main ().
Одна из функций программы драйвера - добавить обзор, который принимаетданные от пользователя и вставляет их во временный объект «Обзор».Затем этот объект передается для вставки в вектор отзывов для соответствующей книги.Вот код для функции addReview () :

void addReview()
{
    string name = "";
    string title;
    Book rTemp;
    cin.ignore();
    cout<<"Which book would you like to rate (Title)?: ";
    getline(cin, name);
    name = toLow(name);
    Review r;
    string re, user;
    int ra;
    cout<<"Username (Full Name): ";
    getline(cin, user);
    string fname = user.substr(0, user.find_first_of(' '));
    string lname = user.substr( user.find_first_of(' ') + 1, user.size());
    r.setUsrFName(fname);
    r.setUsrLName(lname);
    cout<<"Enter rating (1-5):";
    cin>>ra;
    r.setRating(ra);
    cout<<"Enter a short textual review: ";
    cin.ignore();
    getline(cin, re);
    r.setReview(re);
    for(unsigned int i = 0; i < vectBooks.size(); i++)
    {
         title = toLow(vectBooks[i].getTitle());
         if(title.find(name) != string::npos)
         {
             vectBooks[i].getReviews()->push_back(r);
         }
    }
}

Теперь проблема в том, что если я добавляю отзыв, он добавляет его для всех книг.Другими словами, когда я получаю информацию о книге для любой книги, обзор отображается для всех книг.Я предполагаю, что это проблема с указателем, так как кажется, что все отзывы хранятся в одном и том же векторе.Я не уверен, где я испортил, но у меня есть ощущение, что где-то с указателем.Любая помощь приветствуется.

Спасибо

ОБНОВЛЕНИЕ

Смысл в названии этой проблемы заключается в том, что я выполняю заданиеуказатель на вектор Reviews в конструкторе класса Book, из которых эти 2 являются переменными-членами.Для конструктора используйте следующий код:

Book::Book()
{
    pointRev = &vectReviews;
}

ОБНОВЛЕНИЕ 2

Вот код для класса книги и вспомогательных классов:

book.h

#ifndef BOOK_H_
#define BOOK_H_

#include <string>
#include <iostream>
#include <vector>
#include "review.h"

using namespace std;

class Book
{
private:
    string title;
    string author;
    string pubDate;
    string isbn;
    string category;
    string format;
    string synopsis;
    vector<Review> vectReviews;
    vector<Review>* pointRev;
public:
    Book::Book() : pointRev(&vectReviews) {};
    string getAuthor() const;
    string getCategory() const;
    string getFormat() const;
    string getIsbn() const;
    string getPubDate() const;
    string getSynopsis() const;
    string getTitle() const;
    vector<Review>* getReviews();
    void setAuthor(string author);
    void setCategory(string category);
    void setFormat(string format);
    void setIsbn(string isbn);
    void setPubDate(string pubDate);
    void setSynopsis(string synopsis);
    void setTitle(string title);

    friend ostream& operator <<(ostream& out, Book& book);
    vector<Review> *getPointRev() const;
    vector<Review> getVectReviews() const;
    void setPointRev(vector<Review> *pointRev);
    void setVectReviews(vector<Review> vectReviews);


};

#endif /* BOOK_H_ */

book.cpp

#include "book.h"
string Book::getAuthor() const
{
    return author;
}

string Book::getCategory() const
{
    return category;
}

string Book::getFormat() const
{
    return format;
}

string Book::getIsbn() const
{
    return isbn;
}

string Book::getPubDate() const
{
    return pubDate;
}

string Book::getSynopsis() const
{
    return synopsis;
}

string Book::getTitle() const
{
    return title;
}

void Book::setAuthor(string author)
{
    this->author = author;
}

void Book::setCategory(string category)
{
    this->category = category;
}

void Book::setFormat(string format)
{
    this->format = format;
}

void Book::setIsbn(string isbn)
{
    this->isbn = isbn;
}

void Book::setPubDate(string pubDate)
{
    this->pubDate = pubDate;
}

void Book::setSynopsis(string synopsis)
{
    this->synopsis = synopsis;
}

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

vector<Review> *Book::getPointRev() const
{
    return pointRev;
}

vector<Review> Book::getVectReviews() const
{
    return vectReviews;
}

void Book::setPointRev(vector<Review> *pointRev)
{
    this->pointRev = pointRev;
}

void Book::setVectReviews(vector<Review> vectReviews)
{
    this->vectReviews = vectReviews;
}

vector<Review>* Book::getReviews()
{
    return pointRev;
}


ostream& operator <<(ostream& out, Book& book)
{
    out<<"\nTitle: "<<book.getTitle()<<endl;
    out<<"Author: "<<book.getAuthor()<<endl;
    out<<"Publish Date: "<<book.getPubDate()<<endl;
    out<<"ISBN: "<<book.getIsbn()<<endl;
    out<<"Category: "<<book.getCategory()<<endl;
    out<<"Format: "<<book.getFormat()<<endl;
    out<<"Synopsis: "<<book.getSynopsis()<<endl;
    cout<<"\n--- Reviews ---"<<endl;
//  vector<Review>* revs = book.getReviews();
    for(unsigned int h = 0; h < book.getReviews()->size(); h++)
    {
        cout<<"Review by: "<<book.getReviews()->at(h).getUsrFName()<<" "<<book.getReviews()->at(h).getUsrLName()<<endl;
        cout<<"Rating: "<<book.getReviews()->at(h).getRating()<<endl;
        cout<<"Review: "<<book.getReviews()->at(h).getReview()<<endl;
    }

    return out;
}

review.h

#ifndef REVIEW_H_
#define REVIEW_H_

#include <string>

using namespace std;

class Review
{
private:
    int rating;
    string review;
    string usrFName;
    string usrLName;
public:
    int getRating() const;
    string getReview() const;
    void setRating(int rating);
    void setReview(string review);
    string getUsrFName() const;
    string getUsrLName() const;
    void setUsrFName(string usrFName);
    void setUsrLName(string usrLName);
};

#endif /* REVIEW_H_ */

review.cpp

#include "review.h"



int Review::getRating() const
{
    return rating;
}

string Review::getReview() const
{
    return review;
}


void Review::setRating(int rating)
{
    this->rating = rating;
}

string Review::getUsrFName() const
{
    return usrFName;
}

string Review::getUsrLName() const
{
    return usrLName;
}

void Review::setUsrFName(string usrFName)
{
    this->usrFName = usrFName;
}

void Review::setUsrLName(string usrLName)
{
    this->usrLName = usrLName;
}

void Review::setReview(string review)
{
    this->review = review;
}

1 Ответ

1 голос
/ 02 марта 2011

Исходя из описанного вами поведения, конструктор копирования работает и создает два объекта, которые указывают на один и тот же вектор. push_back действительно использует конструктор копирования.

Но ваш первый фрагмент кода не делает кучу копий одного и того же Book, но новый Book создается на каждой итерации цикла (а затем копируется в vectBooks.

Если Book не имеет корректного пользовательского конструктора копирования, значит, вы не управляете pointRev правильно. Исходя из наблюдаемого поведения, я считаю, что у вас есть деструктор, который освобождает pointRev, а затем копия внутри vectBooks остается с висящим указателем. Все, что после этого попадает в категорию неопределенное поведение в соответствии со стандартом, что означает «все может случиться». Затем следующее Book происходит повторное использование той же области памяти, поэтому все экземпляры Book заканчиваются с тем же значением в диком указателе. А затем обновление любого изменяет вектор (который даже не жив), видимый всеми Book экземплярами.

Почему вы все равно используете указатель на std::vector? Гораздо лучше просто поместить вектор в класс в качестве прямого члена данных, что позволяет компилятору автоматически создавать, копировать и уничтожать его без дополнительной помощи с вашей стороны.


Конечно, вполне возможно, что вы сделали vectReviews глобальной переменной, и тогда каждая книга указывает на один и тот же экземпляр. Это приведет к тому, что обзор будет отображаться во всех книгах одновременно, потому что они содержат вектор, к которому вы добавляете его.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...