2013-03-12 178 views
2

第一类是:虚拟功能不能正常工作

class SistemPornire{ 
protected: 
    Motor &_motor; 
    Electromotor &_electromotor; 

public: 
    SistemPornire(Motor&,Electromotor&); 
    virtual void pornire_motor(); 
    void opreste_motor(); 
}; 

虚函数的实现是:

SistemPornire::SistemPornire(Motor &motor, Electromotor &electromotor) 
    :_motor(motor), _electromotor(electromotor) 
{ 
} 

void SistemPornire::pornire_motor() 
{ 
    std::cout << "Sistemul de pornire a trimis comanda porneste_motor electromotorului." << std::endl; 
    this->_electromotor.start(_motor); 
} 

第二类:

class SistemPornireCuPreincalzire:public SistemPornire { 
public: 
    SistemPornireCuPreincalzire(Motor&,Electromotor&); 
    void pornire_motor(); 
}; 

它的实现:

SistemPornireCuPreincalzire::SistemPornireCuPreincalzire(Motor&motor, Electromotor&electromotor) 
    : SistemPornire(motor, electromotor) 
{ 

} 

void SistemPornireCuPreincalzire::pornire_motor() 
{ 
    std::cout << "A inceput preincalzirea" <<std::endl<< "Preincalzirea incheiata" << std::endl; 

    std::cout << "Sistemul de pornire a trimis comanda porneste_motor electromotorului." << std::endl; 
    this->_electromotor.start(_motor); 
} 

在主函数中,我试图调用函数pornire_motor()来处理类型为SistemPornireCuPreincalzire的对象,但它会打印出来自SistemPornire::pornire_motor()函数的消息。

你能告诉我我做错了什么?我提供的信息是否足够?

class Autoturism { 

private: 
    Electromotor electromotor; 
    Motor motor; 
    SistemPornire sistem_pornire; 
    SistemDirectie sistem_directie; 
    CutieViteze cutieviteze; 

public: 
    Autoturism(SistemPornire&, Electromotor&, Motor&, SistemDirectie&); 
    void porneste_autoturism(); 
    void condu_la_destinatie(); 
    void parcheaza_autoturism(); 
}; 

Autoturism::Autoturism(SistemPornire &sp, Electromotor&e, Motor&m, SistemDirectie&sd): sistem_pornire(sp), electromotor(e), motor(m), sistem_directie(sd) 
{ 

} 

void Autoturism::porneste_autoturism() 
{ 
    std::cout << "Comanda porneste_autoturism a fost trimisa catre sistemul de pornire." << std::endl; 
    this->sistem_pornire.pornire_motor(); 
} 

void Autoturism::condu_la_destinatie() 
{ 
    this->porneste_autoturism(); 
    std::cout << "Odata ce masina a pornit, soferul o poate conduce la destinatie." << std::endl; 

    this->cutieviteze.gearUp(); 
    this->sistem_directie.stanga(0); 
    this->cutieviteze.gearUp(); 
    this->cutieviteze.gearUp(); 
    this->cutieviteze.gearDown(); 
    this->sistem_directie.stanga(90); 
    this->cutieviteze.gearUp(); 
    this->sistem_directie.stanga(0); 
    this->cutieviteze.gearDown(); 
    this->sistem_directie.dreapta(30); 
    this->sistem_directie.dreapta(0); 
    this->sistem_directie.dreapta(10); 


    std::cout << "Odata ce s-a ajuns la destinatie masina e gata de a fi parcata." << std::endl; 
    this->parcheaza_autoturism(); 
    std::cout << "Soferul a ajuns la destinatie." << std::endl; 
} 

void Autoturism::parcheaza_autoturism() 
{ 
    std::cout << "Comanda parcheaza_autoturism a fost trimisa catre sistemul de pornire." << std::endl; 
    this->sistem_pornire.opreste_motor(); 
} 

主要功能:

int main() 
{ 
    Motor motor; 
    Electromotor electromotor; 
    SistemPornire sistempornire(motor, electromotor); 
    SistemDirectie sistemdirectie; 
    SistemPornireCuPreincalzire sistempornireINC(motor, electromotor); 

    Autoturism masina(sistempornireINC, electromotor, motor,sistemdirectie); 

    std::cout << "Porneste autoturism:" << std::endl; 
    masina.porneste_autoturism(); 

    std::cout << "Parcheaza autoturism:" << std::endl; 
    masina.parcheaza_autoturism(); 

    std::cout << "Condu la destinatie:" << std::endl; 
    masina.condu_la_destinatie(); 
    return 0; 
} 
+3

我猜对象切片。没有调用代码就无法确定。 – chris 2013-03-12 21:57:42

+9

您能构建一个证明这个问题的[minimal test-case](http://sscce.org)吗? – 2013-03-12 21:57:50

+0

显示主要功能。 – Angew 2013-03-12 21:58:03

回答

4

让我们看看代码的一些部分,分析发生了什么。这是从main代码:

Motor motor; 
Electromotor electromotor; 
SistemPornire sistempornire(motor, electromotor); 
SistemDirectie sistemdirectie; 
SistemPornireCuPreincalzire sistempornireINC(motor, electromotor); 

注意到你如何创建SistemPornireCuPreincalzire这里的实例,你再通入的Autoturism构造:

Autoturism masina(sistempornireINC, electromotor, motor,sistemdirectie); 

让我们来看看Autoturism构造为第二, 我们可以?

Autoturism(SistemPornire&, Electromotor&, Motor&, SistemDirectie&); 

嗯,它需要一个参考SistemPornire和我们传递一个参考SistemPornireCuPreincalzire。这不一定是错误,但它足以让你思考。因此,让我们来看看Autoturism构造做什么:

Autoturism::Autoturism(SistemPornire &sp, Electromotor&e, 
         Motor&m, SistemDirectie&sd) 
    : sistem_pornire(sp), electromotor(e), motor(m), sistem_directie(sd) 
{ 

} 

嗯......什么的sistem_pornire类型?看代码,我们可以看到它的声明如下:

SistemPornire sistem_pornire; 

只是看到这足以解释为什么虚拟功能不工作。 sistem_pornire的类型在编译时已知,并且没有虚拟调度。请记住,虚拟功能仅在您通过指针(即您的必须使用->运算符)调用虚拟功能时才会发生。

但是,让我们挖一个深一点太...

所以构造函数接受一个SistemPornire实例的引用,并用它来初始化sistem_pornire成员的实例中Autoturism。换句话说,您复制构建的sistem_pornire对象与您在main中声明的SistemPornireCuPreincalzireSistemPornire部分。

来自main的对象从未被调用过并且从未使用过。

您应该仔细阅读关于slicing problem和关于virtual functions在C++中的调度。

祝你好运!

3

编辑

在更新的问题,因为@Roddy指出,切片在Autoturism构造发生。

您正在通过将派生对象分配给基础对象来切片您的对象。

SistemPornireCuPreincalzire derived = SistemPornireCuPreincalzire(); 

SistemPornire base = derived; // sliced 

您需要通过引用来引用派生类:

SistemPornireCuPreincalzire derived = SistemPornireCuPreincalzire(); 

SistemPornire& base = derived; // no slicing 

参见:

+1

切片发生在AutoTurism构造函数 – Roddy 2013-03-12 22:13:09

+0

有切片,但这不是*这里的问题。 – 2013-03-12 22:22:22

+0

@NikBougalis为什么切片不是问题? – 2013-03-12 22:41:33