未定义的对象错误引用

时间:2015-05-01 06:43:19

标签: c++ class oop abstract-class

#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;
}

在上面的代码获取中,未定义引用对象错误的行部分myCarBody = mycar-&gt; getBody(); 主函数行。你能帮我解决这个问题吗?请解释 Car * mycar和Car mycar 之间的区别。选择哪一个?

感谢您的帮助。

2 个答案:

答案 0 :(得分:6)

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

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

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

通过调用基类的虚函数,最终会调用覆盖它的派生类的函数。 析构函数也是如此,需要虚拟,以便调用派生类的析构函数并避免未定义的行为。如果在其中一个派生类中有动态分配的数据,则会出现内存泄漏。

此外,在处理多态时,你必须使用指针或引用。它背后的逻辑是指针具有相同的大小,但像Benz这样的派生类可能有额外的数据,不适合Car占用的空间,并会被切片。因此,没有指针或引用,赋值/复制构造就无法正常工作。

建议发表评论:

  • 访问者功能(“getters”和“setters”)通常带有 私人或受保护的成员。你的是公共的,访问者是 没用,可以规避。保留访问者,制作数据 私人的。当你返回一个成员时,你可以通过 引用给const。但不要为getEnginegetWheelsgetBody执行此操作 std::string const& getSpec() { return spec; } ,因为他们返回的是本地对象,而不是成员。

    std::string

    虽然我们正在使用它,但您也可以通过引用传递给Part(std::string const& str) : spec(str) {}

    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

您还忘记删除<RelativeLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" > <ImageView android:id="@+id/uivProfileImage" android:layout_width="100dp" android:layout_height="100dp" android:layout_marginLeft="10dp" android:layout_marginStart="10dp" android:adjustViewBounds="true" android:contentDescription="@null" android:maxHeight="100dp" android:maxWidth="100dp" android:scaleType="fitXY" /> <ImageView android:id="@+id/uivProfileCoverImage" android:layout_width="match_parent" android:layout_height="100dp" android:layout_marginLeft="10dp" android:layout_marginRight="10dp" android:layout_toRightOf="@+id/uivProfileImage" android:adjustViewBounds="true" android:contentDescription="@null" android:maxHeight="100dp" android:scaleType="fitXY" /> </RelativeLayout> ,请在其他答案中查看更多有关信息。

答案 1 :(得分:5)

首先,如果您想使用polymorphism,则需要将函数声明为virtual

如果您不打算在基类中实现方法,可以将它们声明为pure virtual。这使你的基类所谓的&#34; abstract&#34;并且您将无法创建该类的对象(在您的示例中,最佳候选者是Car对象)。

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

所以你需要把所有东西放在一起:

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

因此,你对编译器说的问题的根本原因&#34;嘿,我将实施Car&#34;的方法。但还没有完成。所以编译器期望从你的main调用那些方法,但在linking阶段链接器上找不到它们。

您需要考虑的另一个问题:

  1. 谁将摧毁由&#34; new&#34;创建的对象。我建议不要 考虑一下并使用shared(智能)指针(参见 std :: shared_pointer容器)。
  2. 当您从字符串声明Part类的构造函数时,您声明创建的可能性来自字符串的部分作为部分x =&#34;部件名称&#34 ;;如果您不喜欢这种行为,请阅读&#34; explicit&#34;关键字。
  3. 正如在对更大项目的评论中所说,你需要考虑encapsulation隐藏&#34;私有&#34;中对象实现的细节。课程的各个部分。