【问题标题】:C++ Pointer Assignment in custom class constructor自定义类构造函数中的 C++ 指针赋值
【发布时间】:2011-03-02 05:41:47
【问题描述】:

所以我有一个自定义类“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);
         }
    }
}

现在的问题是,如果我添加评论,它会为所有书籍添加评论。换句话说,当我获取任何书籍的书籍信息时,评论会显示在所有书籍上。我认为这是指针的问题,因为似乎所有评论都存储在同一个向量中。我不确定我在哪里搞砸了,但我感觉指针在某个地方。任何帮助表示赞赏。

谢谢

更新

指向这个问题的标题是我在Book类的构造函数中将指针分配给Reviews的向量,其中这2个是成员变量。构造函数代码如下:

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

更新 2

这是 Book Class 和支持类的代码:

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_ */

书。 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;
}

【问题讨论】:

  • while (!file.eof()) 不是编写输入循环的正确方法。正确方法见GMan对one of the Stack Overflow C++ FAQ questions的回答。
  • 在 ctor 中,人们应该更喜欢使用初始化列表而不是 ctor 主体中的赋值。
  • @James:感谢您指出这一点。
  • @STATUS_ACCESS_DENIED :你能给我举个例子吗?我不确定你的意思。
  • 很难在评论中,但让我试试:Book::Book() : pointRev(&amp;vectReviews) {} ...

标签: c++ class pointers vector


【解决方案1】:

根据您描述的行为,复制构造函数正在运行并生成两个指向同一向量的对象。 push_back 确实使用了复制构造函数。

但是您的第一个代码 sn-p 不会复制相同的Book,而是在每次循环迭代时创建一个新的Book(然后复制到vectBooks

如果Book 没有正确的用户定义的复制构造函数,那么您就没有正确管理pointRev。从观察到的行为,我相信你有一个释放pointRev 的析构函数,然后vectBooks 中的副本留下了一个悬空指针。这之后的一切根据标准都属于未定义行为的范畴,意思是“任何事情都可能发生”那么接下来的Book恰好重用了同一个内存区域,所以Book的所有实例最终在野指针中得到相同的值。然后更新任何一个都会更改所有Book 实例看到的向量(甚至不再存在)。

你为什么要使用指向std::vector 的指针呢?最好将向量作为直接数据成员放入类中,这样编译器就可以自动构造、复制和破坏它,而无需您提供额外的帮助。


当然,您完全有可能将vectReviews 设为全局变量,然后每一本书都指向同一个实例。这将同时出现在所有书籍中,因为它们共享您要添加它的向量。

【讨论】:

  • @Ben:我还没有设置任何析构函数。我并没有真正完成这个项目的编码,现在它让我忘记了。另外,我不确定我为什么要使用向量是什么意思。驱动程序并没有真正的类。只是一个 main() 函数,它从文件中读取所有内容,然后是一个开关式菜单,提供用于操作书籍和评论的选项。因此,我将这些 Book 对象存储在驱动程序中全局声明的向量中,每个 Book 对象都有一个相应的评论向量,用于存储来自多个用户的评论。
  • @blazethesinner:vectBooks 来自哪里?您正在获取它的地址,但该指针只有在原始对象还活着时才有效。
  • 但无论如何,我还没有设置任何析构函数。你能举一个复制构造函数的例子吗?或者在这种情况下会是什么样子?
  • stackoverflow.com/questions/4172722/what-is-the-rule-of-three 我不是在问你为什么要使用向量,我是在问为什么你的类有一个指向向量的指针,而不仅仅是一个向量。
  • @Ben :回答你的问题,这是因为传递指针比传递整个向量更容易,我不知道该怎么做,因为我需要通过引用传递它向量是'Book' 类的私有成员。
猜你喜欢
  • 1970-01-01
  • 2013-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-04-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多