未定义的对象引用错误

undefined reference to object error

#include <iostream>
#include <string>
using namespace std;

class Part{
public:
    std::string spec;
    Part(std::string str){
        this->spec = str;
    }
    std::string getSpec(){
        return spec;
    }
};

class Car{
public:
    Part getEngine();
    Part getWheels();
    Part getBody();
};


class Benz:public Car{
public:
    Part getEngine(){
        return Part("Benz Engine");
    }   
    Part getWheels(){
        return Part("Benz Wheels");
    }
    Part getBody(){
        return Part("Benz Body");
    }
};

class Audi:public Car{
public:
    Part getEngine(){
        return Part("Audi Engine");
    }   
    Part getWheels(){
        return Part("Audi Wheels");
    }
    Part getBody(){
        return Part("Audi Body");
    }
};

class CarFactory{
public:
    Car *pcar;
    Car *getCar(std::string carType){
        if (carType.compare("Benz") == 0){
            pcar = new Benz();
        }else if (carType.compare("Audi") == 0){
            pcar = new Audi();
        }
        return pcar;
    }
};

int main(){
    CarFactory *cf = new CarFactory();
    Car *mycar = cf->getCar("Benz");
    Part myCarBody = mycar->getBody();
    cout <<myCarBody.getSpec() <<endl;
    //cout << mycar->getBody().getSpec() <<endl;
}

在上面的代码中,在main函数的第Part myCarBody = mycar->getBody();行获取对象错误的未定义引用。你能帮我解决这个问题吗?请解释一下 Car *mycar 和 Car mycar 之间的区别。什么时候选哪个?

感谢您的帮助。

Car 的成员函数应该是 纯虚拟的 而不是你的非虚拟声明:

class Car
{
public:
    virtual ~Car() = default;     // Virtual destructor
    virtual Part getEngine() = 0;
    virtual Part getWheels() = 0;
    virtual Part getBody() = 0;
};

这就是链接器错误的原因。 编译器需要 Car 的函数定义,因为这些函数不是纯虚拟的,但找不到它。
使用纯虚拟成员函数,Car 成为抽象 class 并提供一个接口(纯虚拟),必须由 classes 派生实现从中。否则,派生的 class 也将是抽象的并且不可实例化。

通过调用基类 class 的虚函数,您最终会调用派生 class 的函数来覆盖它。 Destructor也是如此,需要做成virtual,为了调用派生class的析构函数,避免未定义的行为.如果您在派生的 classes 之一中有动态分配的数据,就会发生内存泄漏。

此外,在处理多态性时,您必须使用指针或引用。它背后的逻辑是指针具有相同的大小,但是像 Benz 这样的派生 class 可能有额外的数据并且不适合 Car 占用的 space 并且会变成切片。因此,assignment/copy 构造在没有指针或引用的情况下无法正常工作。

评论中建议:

  • 访问函数("getters"和"setters")通常带有 私人或受保护的成员。你的是public,存取器是 无用且可以规避。保留存取器,制作数据 私人的。当您退回会员时,您可以通过 引用到常量。但不要为 getEnginegetWheelsgetBody,因为他们返回的是本地对象,而不是成员。

    std::string const& getSpec() { return spec; }
    

    当我们这样做时,您也可以通过对常量的引用来传递 std::string

    Part(std::string const& str) : spec(str) {}
    
  • 工厂class

    class CarFactory
    {
    public:
        Car *getCar(std::string const& carType)
        {
            if(carType == "Benz") // std::string::compare is for comparing by alphabetical order
                return new Benz();
    
            if(carType == "Audi")
                return new Audi();
    
            return nullptr; // invalid carType, return nullptr and check for that in main()
            // You were returning previously constructed Car, was that desired?
        }
    };
    

你也忘记删除了myCar,在其他答案中查看更多有用的信息。

首先如果你想使用polymorphism you need to declare functions as virtual

如果您不打算在基础 class 中实现方法,您可以将它们声明为 pure virtual. This make your base class so called "abstract",并且您将无法创建 class 的对象(在您的例如最佳候选对象是 Car 对象)。

还要小心。如果你想通过指向基 class 的指针销毁对象,你还需要 virtual destructor.

因此,要将所有内容放在一起,您需要:

class Car {
public:
    virtual ~Car() {}
    virtual Part getEngine() = 0;
    virtual Part getWheels() = 0;
    virtual Part getBody() = 0;
};

所以问题的根本原因是您对编译器 "Hey, I'm going to implement methods of Car" 说但没有做到。因此,编译器希望从您的 main 中调用该方法,但在 linking 阶段链接器找不到它们。

您需要思考的其他问题:

  1. 谁将销毁您由 "new" 创建的对象。我建议不要 考虑一下并使用 shared (智能)指针(请参阅 std::shared_pointer 容器)。
  2. 当您从字符串声明 Part class 的构造函数时,您声明了从字符串创建 Parts 的可能性,如 Part x = "Part Name";如果您不喜欢这种行为,请阅读“explicit”关键字。
  3. 正如在针对更大项目的评论中所说,您需要考虑 encapsulation 在 class es 的 "private" 部分隐藏对象实现的细节。