虚拟功能不起作用

时间:2013-03-12 21:56:10

标签: c++ virtual-method

第一堂课是:

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

在main函数中,我试图为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;
}

2 个答案:

答案 0 :(得分: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_pornireAutoturism成员的实例。换句话说,您使用sistem_pornire中声明的SistemPornire的{​​{1}}部分复制构造SistemPornireCuPreincalzire对象。

来自main的对象永远不会被调用,也永远不会被使用。

您应该仔细阅读C ++中的slicing problemvirtual functions调度。

祝你好运!

答案 1 :(得分:3)

修改

在更新的问题中,正如@Roddy指出的那样,切片发生在Autoturism构造函数中。

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

SistemPornireCuPreincalzire derived = SistemPornireCuPreincalzire();

SistemPornire base = derived; // sliced

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

SistemPornireCuPreincalzire derived = SistemPornireCuPreincalzire();

SistemPornire& base = derived; // no slicing

请参阅: