2015-05-01 59 views
0
#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-> getBody到对象错误();主功能线。你可以帮我固定这一点,也请解释汽车* mycar和车mycar之间的差异。哪一个选择什么时候?未定义参照对象错误

感谢您的帮助。的Car

+0

'Car * mycar'是指向'Car'的指针; '汽车mycar'是一个实际的'汽车'对象。你需要在指针上使用箭头(' - >')符号;你需要在对象中使用点('.')符号。在这种情况下,指针比对象更有可能是有益的。这往往是这样,但并非总是如此。 –

+0

这段代码中的继承模型有很多不足之处。所有'Benz'对象都表现相同;所有的'奥迪'对象都表现相同。那很糟。这是古董,但汤姆嘉吉的书[C++编程风格](http://www.amazon.com/C-Programming-Style-Tom-Cargill/dp/0201563657)详细讨论了这个和其他一些常见问题。 –

+0

@Kranthi请接受任一答案。是时候了。 – LogicStuff

回答

6

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

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

这就是为什么连接错误。 编译器预计Car的函数定义因为这些功能不是纯虚拟的,但它无法找到它。
随着纯虚拟成员函数,Car成为一个抽象类和提供一个接口(纯虚拟的),必须通过从它派生的类来实现。否则,派生类也将是抽象的,不可实例化。

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

此外,您必须使用指针或引用时处理多态性。其背后的逻辑是指针具有相同的大小,但派生类如Benz可能有额外的数据,并且不适合Car所占用的空间,并且会变得切片。因此,如果没有指针或引用,分配/复制结构将无法正常工作。

提出在评论:

  • 访问函数( “干将” 和 “二传手”)通常会用 私有或受保护的成员。你的公开,访问者是 没用,可以绕过。保留访问者,使数据 私有。当你回来的一员,您可以通过 引用给const做到这一点。但是不要为getEngine,getWheelsgetBody这样做,因为它们返回的是本地对象而不是成员。

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

    虽然我们在这,你可以参考给const通过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,看到对方的回答更良好的信息。

+1

正确。但是代码中还有其他一些不好的东西。我看到evrywhere的公共数据成员不是一个虔诚的想法。如果给定字符串不是奔驰和奥迪,则在工厂类中将返回nullptr。 –

+2

@vizhanyolajos不仅这样的问题 - 对象复制,创建的可能性部分隐含从std :: string,内存泄漏... –

5

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

如果你不打算在基类中实现方法,你可以声明它们为pure virtual。这使得你的基类被称为“abstract”,你将不能创建该类的对象(在你的例子中最好的候选对象是Car对象)。

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

所以把所有在一起,你需要:

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

所以你的问题的根本原因,你说编译器“嘿,我要实现汽车的方法”,但不这么做。所以编译器有望从你的main调用该方法,但在linking阶段链接器找不到它们。

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

  1. 谁将摧毁你的“新”创建的对象。我建议不要 想一想,并使用shared(智能)指针(请参阅 std :: shared_pointer容器)。
  2. 当您从字符串中声明Part类的构造函数时,您声明可以从字符串中创建Part作为Part x =“Part Name”;如果您不喜欢此行为,请阅读“explicit”关键字。
  3. 正如在大型项目的评论中所说的,您需要考虑encapsulation在类的“私人”部分隐藏对象实现的细节。
+0

嗨,很好解释。你能告诉我示例代码如何在我的代码中使用智能指针。 – Kranthi

+0

只需将车*替换为std :: shared_ptr

+0

而且当您创建对象时使用std :: shared_ptr (新奔驰) –

相关问题