简体   繁体   English

C++,运行时错误:成员调用 null 类型的指针

[英]C++,runtime error: member call on null pointer of type

First of all, I am new here to c++ and I'm trying to learn it.首先,我是 c++ 的新手,我正在努力学习它。 Also new to stackoverflow.也是 stackoverflow 的新手。 Find it quite hard to be honest.发现很难说实话。 If you have additional comments in terms of my code and how i can improve it, please let me know as I am still in the learning process.如果您对我的代码以及我如何改进它有其他意见,请告诉我,因为我仍在学习过程中。

ok I was I just creating a online booking system using object oriented programming.好的,我只是使用面向 object 的编程创建了一个在线预订系统。

Ok so the main issue is that I dont understand why system.setDisplay(1234);好的,主要问题是我不明白为什么system.setDisplay(1234); isn't printing anything.没有打印任何东西。 I have tried everything and just isn't adding up.我已经尝试了一切,只是没有加起来。 OnlineBookingSystem is the class is being used to call setDisplay(id) which then invoked the display class. If you can help it would mean the world to me and the error i`m getting is: OnlineBookingSystem 是 class 用于调用 setDisplay(id),然后调用显示 class。如果你能提供帮助,这对我来说意义重大,我得到的错误是:

runtime error: member call on null pointer of type 'User' (solution.cpp) SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior prog_joined.cpp:179:54运行时错误:成员调用“用户”类型的指针 null (solution.cpp) 摘要:UndefinedBehaviorSanitizer:undefined-behavior 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,size_t id,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;
}

Problems I see:我看到的问题:

Problem 1问题1

Since the return type of OnlineBookingSystem::getLibrary() is Library , the line由于OnlineBookingSystem::getLibrary()的返回类型是Library ,该行

auto lib=system.getLibrary();

construct lib as a copy of the object in system .lib构造为system中 object 的副本。 Any changes made to lib are changes to the copy, not to the Library object in system .lib所做的任何更改都是对副本的更改,而不是对system中的Library object 的更改。

To fix the problem, change the return type to a reference:要解决此问题,请将返回类型更改为引用:

Library& getLibrary()
{
    return library;
}

and capture the return value also as a reference in main .并捕获返回值也作为main中的参考。

auto& lib=system.getLibrary();

Problem 2问题2

Similar to Problem 1 but this time it is in OnlineBookingSystem::getUserManager .与问题 1 类似,但这次是在OnlineBookingSystem::getUserManager中。 Change its return type to be a reference:将其返回类型更改为引用:

UserManager& getUserManager()
{
    return manager;
}

and capture the return value also as a reference in main .并捕获返回值也作为main中的参考。

auto& manager=system.getUserManager();

Problem 3问题3

Adopt defensive programming at every step until something is a performanced bottleneck.在每一步都采用防御性编程,直到出现性能瓶颈。 If a return value of a function can be nullptr , check the return value at the point of invocation and deal with the case when the return value is indeed nullptr .如果 function 的返回值可以是nullptr ,则在调用时检查返回值,当返回值确实为nullptr时进行处理。

Update OnlineBookingSystem::setDisplay to: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;
        }
    }

The problem问题
It comes down to your call to system.getUserManager() returning a copy of OnlineBookingSystem 's manager field, instead of a pointer to it.它归结为您调用system.getUserManager()返回OnlineBookingSystemmanager字段的副本,而不是指向它的指针

As a result, when you call manager.addToQueue("Michael") , it is adding Michael to the UserManager instance that is local to int main() , instead of the instance that's held in system .因此,当您调用manager.addToQueue("Michael")时,它会将 Michael 添加到int main()本地的UserManager实例,而不是system中保存的实例。

Your function OnlineBookingSystem::setDisplay(size_t) makes a call to manager.getNextCustomer() .您的 function OnlineBookingSystem::setDisplay(size_t)调用manager.getNextCustomer() Because you've added Michael to a different instance of manager , this returns nullptr .因为您已将 Michael 添加到manager的不同实例,所以这将返回nullptr

How to fix it如何修复
You simply need to modify OnlineBookingSystem::getUserManager() to return a pointer to manager instead of a copy of it:您只需要修改OnlineBookingSystem::getUserManager()以返回指向manager的指针而不是它的副本:

UserManager* getUserManager()
{
    return &manager;
}

Then modify the calling code to use the pointer dereference operator ( -> ) instead of a period to access methods on manager .然后修改调用代码以使用指针取消引用运算符 ( -> ) 而不是句点来访问manager上的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM