从基类指针调用派生类非虚拟成员函数

时间:2017-07-17 17:56:21

标签: c++ c++11 inheritance virtual virtual-functions

我们知道,派生类成员函数可以通过C ++中的基类指针访问,提供这些成员函数必须是虚拟的。有没有办法从基类指针访问派生类成员函数非虚拟或纯虚拟

即。我想调用派生类成员函数,它们只出现在派生类和放大器中。通过基类指针不在基类中。我怎么做到这一点?

例如,如果我设计工厂设计模式,

from vlc import Instance

playlist = ['/home/user/Music/01 Signs.mp3','/home/user/Music/2U.mp3']
player = Instance()
mediaListPlayer = player.media_list_player_new()
mediaList = player.media_list_new()
for element in playlist:
    mediaList.add_media(player.media_new(element))
mediaListPlayer.set_media_list(mediaList)
mediaListPlayer.play()
mediaListPlayer.audio_set_volume(80)

3 个答案:

答案 0 :(得分:1)

  

我想调用仅在派生类&中出现的派生类成员函数。通过基类指针不在基类中。我怎么做到这一点?

您不能使用指向基类的指针调用派生类的非虚成员函数。

您需要一个指向派生类的指针。最简单的方法是使用dynamic_cast获取指向派生类的指针,检查转换是否成功,然后使用派生类指针调用派生类成员函数。

更好的方法是在基类中提供虚拟成员函数并在派生类中实现它。

答案 1 :(得分:1)

您可以使用dynamic_cast执行所需操作,但这会导致代码审核结果令人失望。相反,我推测你使用与printVehicle

相同的路线
class Vehicle
{
public:
    // without a virtual destructor you are walking into
    // a very bad bug. The wrong destructor may be called.
    virtual ~Vehicle()
    {
    } 
    virtual void printVehicle() = 0;

    // Specific stuff that all children must provide
    virtual void doTypeSpecificStuff() = 0;

    // this is actually a bit of a ideological weird. I'm not sure I can call
    // it a flaw. By making this factory function a member of Vehicle, Vehicle
    // must now know its children. If this is the case, the VehicleType enum
    // should probably be a member of Vehicle, but personally I think this
    // factory should be a totally free function.
    static Vehicle* Create(VehicleType type);
};
class TwoWheeler: public Vehicle
{
public:
    void printVehicle()
    {
        cout << "I am two wheeler" << endl;
    }
    void doTypeSpecificStuff()
    {
        cout << "Doing two wheeler stuff" << endl;
    }
};

省去其他两个班级Vehicle::Create以节省空间。

int main()
{
    Vehicle* basePtr = Vehicle::Create(VT_TwoWheeler);
    basePtr->doTypeSpecificStuff(); //HOW TO ACHIEVE THIS CALL
    // leaking memory here, so
    delete basePtr;
    // but also look into std::unique_ptr. Much better suited to this behaviour


}

事实上,让我们立即就std::unique_ptr的最终评论采取行动。 unique_ptr为您管理动态分配,因此您不必使用delete来混淆代码,并且可能会错过一个或delete过早的风险。只要unique_ptr在范围内,unique_ptr指针就有效。如果你可以编译,指针是好的,除非你做了一些愚蠢的事情,就像从来没有指向任何东西或手动删除指针。

虽然我们正在努力,但我们已经消除了我之前关于vehicle::Create的担忧。

首先,我们定义一个自由函数来替换Create并返回unique_ptr。由于我不想在我的代码中进行if (ptr != NULL)检查以确保确实创建了一个对象,所以当我们无法匹配所提供的车辆类型时,我们也会对它产生很大的影响。通过抛出异常与类。

而不是if - else if链,我们会使用更优雅的switch语句。

std::unique_ptr<Vehicle> SmarterVehicleFactory(VehicleType type)
{
    switch (type)
    {
        case  VT_TwoWheeler:
            return std::make_unique<TwoWheeler>();
        case  VT_ThreeWheeler:
            return std::make_unique<ThreeWheeler>();
        case  VT_FourWheeler:
            return std::make_unique<FourWheeler>();
        default:
            throw std::runtime_error("Invalid Vehicle type");
    }
}    

然后我们将使用这个新功能

int main()
{
    try
    {
        std::unique_ptr<Vehicle> basePtr = SmarterVehicleFactory(VT_TwoWheeler);
        basePtr->doTypeSpecificStuff();

        basePtr = SmarterVehicleFactory(VT_ThreeWheeler); 
        // unique_ptr freed the TwoWheeler for us.
        basePtr->doTypeSpecificStuff(); 

        basePtr = SmarterVehicleFactory(VT_FourWheeler);
        basePtr->doTypeSpecificStuff(); 

        // just for laughs we will ask for a FiveWheeler, which we have not yet 
        // fully implemented
        basePtr = SmarterVehicleFactory(VT_FiveWheeler);  // will throw exception
        basePtr->doTypeSpecificStuff(); // will not be executed
    }
    catch (const std::exception & exc)
    {
        cerr << "Rats! Something bad happened: " << exc.what();
        // basePtr will be unmodified and still pointing to a FourWheeler
    }
} // basePtr  will go out of scope here and clean up our memory for us.

这种方法的美妙之处在于,没有一个班级知道任何其他课程。您可以将Vehicle放入带有SmarterVehicleFactory原型和车辆类型列表的标题中,并隐藏其他所有内容。用户什么也看不见。每个人都被置于黑暗中。

为什么那么好?因为现在您可以更改除Vehicle接口类之外的任何上述类,而不会对任何其他类产生任何影响。这使您的代码更易于维护和调试。

答案 2 :(得分:0)

我试图找到不使用继承而使用多态的最佳方法,因为我想避免虚拟调用。我正在寻找一种方法来改进我目前拥有的东西(无济于事),我偶然发现了这个问题。这是我目前能做的最好的:

template<class VehicleDetails>
class Vehicle {
    VehicleDetails details;

public:
    VehicleDetails& getDetails() {
        return details;
    }

    const VehicleDetails& getDetails() const {
        return details;
    }

    void printDetails() const {
        details.printDetails();
    }
}

class TwoWheeler {
public:
    void printDetails() const {
        cout << "I am two wheeler" << endl;
    }

    void specificTwoWheelerMethod() const {
        cout << "I am specific functionality" << endl;
    }
}

然后你就这样使用它:

Vehicle<TwoWheeler> vehicle;
vehicle.printDetails(); // prints "I am two wheeler"

不幸的是,这使事情变得复杂。现在,除非您知道车辆的类型,否则每个接受车辆的类/结构或函数都必须进行模板化。

template<class VehicleDetails>
void doGeneralVehicleThings(const Vehicle<VehicleDetails>& vehicle) {
    // ...
}

从好的方面来说,当您知道类型时,您可以通过 getDetails() 方法访问特定功能,而无需涉及任何转换或运行时开销:

void doTwoWheelerThings(const Vehicle<TwoWheeler>& twoWheelerVehicle) {
    twoWheelerVehicle.getDetails().specificTwoWheelerMethod(); // prints "I am specific functionality"
}