C ++,运行时错误:类型的空指针上的成员调用 问题1 问题2 问题3

问题描述

首先,我对C ++还是陌生的,我正在尝试学习它。也是stackoverflow的新功能。 很难做到诚实。 如果您在我的代码以及如何改进它方面还有其他意见,请告诉我,因为我仍在学习过程中。

好吧,我只是使用面向对象的程序创建了一个在线预订系统。

好的,所以主要的问题是我不理解为什么 system.setdisplay(1234); 没有打印任何内容。我已经尝试了一切,只是没有加起来。 OnlineBookingSystem是用于调用setdisplay(id)的类,该类随后调用显示类。 如果您能提供帮助,那对我来说意味着世界,而我得到的错误是:

运行时错误:类型为“用户”(solution.cpp)的空指针上的成员调用 摘要:UndefinedBehaviorSanitizer:未定义行为prog_joined.cpp:179:54

#include <vector>
#include <string>
#include <iostream>
#include <memory>
#include <queue>
using namespace std;

enum class BookGenre
{
    Horror,Adventure,Romance,Comic
};
class Book
{
    private:
        BookGenre genre;
        string title;
        size_t id;
    public:
        Book(string title,size_t id,BookGenre genre):title(title),id(id),genre(genre){}
        string getTitle(){return title;}
        size_t getId(){return id;}
        BookGenre getGenre(){return genre; }
};
class Library
{
    private:
        vector<shared_ptr<Book>> listofBooks;
    public:
        Library(){};
        void addBook(string title,BookGenre genre)
        {
            listofBooks.push_back(make_shared<Book>(title,id,genre));
        }
        shared_ptr<Book> getBook(size_t id)
        {
            for(auto&x:listofBooks)
            {
                if(x->getId()==id)
                {
                    return x;
                }
            }
            return nullptr;
        }
        void removeBook(size_t id)
        {
            for(auto it=listofBooks.begin();it!=listofBooks.end();it++)
            {
                if((*it)->getId()==id)
                {
                    listofBooks.erase(it);
                }
            }
        }
};
class User
{
    protected:
        size_t id;
        string username;
     
    public:
        User(size_t id,string username):id(id),username(username)
        {
 
        }
        virtual ~User(){}
        size_t getId(){return id;}
        string getUsername(){return username;}

};
class Employee:public User{
    private:
        double salary;
    public:
        Employee(size_t id,string username,double salary):User(id,username),salary(salary)
        {
        }
        void setSalary(double salary)
        {
            this->salary=salary;
        }
        double getSalary(){return salary;}
     
};
class Customer:public User{
    private:
           bool membership;
    public:
        Customer(size_t id,string username):User(id,username)
        {
            membership=false;
        }
        void setMemberActive()
        {
            membership=true;
        }
        bool isMemberActive()
        {
            return membership;
        }
};
class UserManager
{
    private:
        vector<shared_ptr<User>>listofUsers;
        queue<shared_ptr<Customer>>queue;
    public:
        UserManager()
        {

        }
      
        void addCustomer(size_t id,string username)
        {
            listofUsers.push_back(make_shared<Customer>(id,username));
        }
        void removeCustomer(string username)
        {
            for(auto it=listofUsers.begin();it!=listofUsers.end();it++)
            {
                if(dynamic_pointer_cast<Customer>(*it))
                {
                    if((*it)->getUsername()==username)
                    {
                        listofUsers.erase(it);
                    }
                }
            }
        }
        shared_ptr<Customer> getCustomer(string username)
        {
            for(auto it=listofUsers.begin();it!=listofUsers.end();it++)
            {
                if(dynamic_pointer_cast<Customer>(*it))
                {
                    if((*it)->getUsername()==username)
                    {
                        return dynamic_pointer_cast<Customer>(*it);
                    }
                }
            }
            return nullptr;
        }
        void addToQueue(string username)
        {
            queue.push(getCustomer(username));
        }
        void removeCurrentCustomer()
        {
            queue.pop();
        }
        shared_ptr<Customer> getNextCustomer()
        {
            if(queue.empty())
            {
                return nullptr;
            }
            return queue.front();
        }
        /*
            same process for user;
        */
};
class display
{   
    private:
        shared_ptr<Customer> m_customer;
        shared_ptr<Book> m_book;
    public:
        display(shared_ptr<Customer> _customer,shared_ptr<Book> _book ):m_customer(_customer),m_book(_book)
        {

        }
        shared_ptr<Customer> getUser(){return m_customer;}
        shared_ptr<Book> getBook(){return m_book;}
        void displayInfo()
        {
            cout<<"Customer username: "<<m_customer->getUsername()<<endl;
            cout<<"Member Active: "<<m_customer->isMemberActive();
            cout<<"book id: "<<m_book->getId()<<endl;
            cout<<"book title: "<< m_book->getTitle()<<endl;
        }

};
class OnlineBookingSystem
{
    private:
        UserManager manager;
        Library library;
        shared_ptr<display>display;
    public:
        OnlineBookingSystem()
        {
            UserManager manager;
            Library library;
            this->manager=manager;
            this->library=library;
            this->display=nullptr;
        }
        Library getLibrary()
        {
            return library;
        }
        UserManager getUserManager()
        {
            return manager;
        }
        void  setdisplay(size_t id)
        {
            display=make_shared<display>( manager.getNextCustomer(),library.getBook(id));
            display->displayInfo();
        }
        shared_ptr<display> getdisplay()
        {
            return this->display;
        }
};
int main()
{

    OnlineBookingSystem system;
    auto lib=system.getLibrary();
    lib.addBook("Adventure of Pablo",1234,BookGenre::Adventure);
    auto manager=system.getUserManager();
    manager.addCustomer(2020,"Michael");
    auto _customer=  manager.getCustomer("Michael");
    _customer->setMemberActive();
    manager.addToQueue("Michael");
    system.setdisplay(1234);

    return 0;
}

解决方法

我看到的问题:

问题1

由于OnlineBookingSystem::getLibrary()的返回类型为Library,因此该行

auto lib=system.getLibrary();

lib构造为system中对象的副本。对lib所做的任何更改都是对副本的更改,而不是对Library中的system对象的更改。

要解决此问题,请将返回类型更改为引用:

Library& getLibrary()
{
    return library;
}

并在main中捕获返回值作为参考。

auto& lib=system.getLibrary();

问题2

类似于问题1,但是这次在OnlineBookingSystem::getUserManager中。将其返回类型更改为引用:

UserManager& getUserManager()
{
    return manager;
}

并在main中捕获返回值作为参考。

auto& manager=system.getUserManager();

问题3

在每一步都采用防御性编程,直到出现性能瓶颈。如果函数的返回值可以为nullptr,请在调用时检查返回值,并处理返回值确实为nullptr的情况。

OnlineBookingSystem::setDisplay更新为:

    void  setDisplay(size_t id)
    {
        display=make_shared<Display>( manager.getNextCustomer(),library.getBook(id));
        if ( display )
        {
            display->displayInfo();
        }
        else
        {
           // Deal with the nullptr case
           std::cout << "Unable to find a book with id " << id << std::endl;
        }
    }
,

问题
这取决于您调用system.getUserManager()返回OnlineBookingSystem的{​​{1}}字段的副本,而不是返回 pointer

因此,当您调用manager时,它会将Michael添加到manager.addToQueue("Michael")本地的UserManager实例中,而不是保存在int main()中的实例中

您的函数system调用OnlineBookingSystem::setDisplay(size_t)。由于您已将Michael添加到manager.getNextCustomer()的其他实例中,因此返回manager

如何修复
您只需要修改nullptr即可返回指向OnlineBookingSystem::getUserManager()的指针,而不是其副本:

manager

然后修改调用代码以使用指针取消引用运算符(UserManager* getUserManager() { return &manager; } )而不是句点来访问->上的方法。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...