从基类指针调用派生类非虚拟成员函数 [英] Call derived class non virtual member functions from base class pointer

查看:102
本文介绍了从基类指针调用派生类非虚拟成员函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

We know that, derived class members functions can be accessed through a base class pointer in C++ , provided that these member functions have to be virtual. Is there a means to access derived class member functions which are NOT virtual or pure virtual from base class pointer.

即我想调用仅在派生类&中存在的派生类成员函数.通过基类指针不在基类中.我将如何实现呢?

i.e. I want to call derived class member functions which are present only in derived class & not in base class through base class pointer. How would I achieve this?

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

For example, if I design a factory design pattern,

class Vehicle {
public:
    virtual void printVehicle() = 0;
    static Vehicle* Create(VehicleType type);
};
class TwoWheeler : public Vehicle {
public:
    void printVehicle() {
        cout << "I am two wheeler" << endl;
    }
    void Some2WheelerONLYSpecificOPeration()
    {

    }
};
class ThreeWheeler : public Vehicle {
public:
    void printVehicle() {
        cout << "I am three wheeler" << endl;
    }
void Some3WheelerONLYSpecificOPeration()
    {

    }
};
class FourWheeler : public Vehicle {
    public:
    void printVehicle() {
        cout << "I am four wheeler" << endl;
    }
void Some4WheelerONLYSpecificOPeration()
    {

    }
};

// Factory method to create objects of different types.
// Change is required only in this function to create a new object type
Vehicle* Vehicle::Create(VehicleType type) {
    if (type == VT_TwoWheeler)
        return new TwoWheeler();
    else if (type == VT_ThreeWheeler)
        return new ThreeWheeler();
    else if (type == VT_FourWheeler)
        return new FourWheeler();
    else return NULL;
}

int main()
{
Vehicle* basePtr =   Vehicle::Create(VT_TwoWheeler);
basePtr->Some2WheelerONLYSpecificOPeration();   //HOW TO ACHIEVE THIS CALL

basePtr =   Vehicle::Create(VT_ThreeWheeler);
basePtr->Some3WheelerONLYSpecificOPeration(); //HOW TO ACHIEVE THIS CALL

basePtr =   Vehicle::Create(VT_FourWheeler);
basePtr->Some4WheelerONLYSpecificOPeration(); // //HOW TO ACHIEVE THIS CALL
}

推荐答案

您可以使用dynamic_cast进行所需的操作,但这会导致代码审查时的结果令人失望.相反,我向您推荐了与printVehicle

You can do what you want with dynamic_cast, but this will lead to disappointing results at a code review. Instead, I pitch you go the same route you did with 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以节省空间.

Leaving out the other two classes and Vehicle::Create to save space.

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的指针就一直有效.如果可以编译,则指针是好的,除非您做一些愚蠢的事情,例如永远不要将其指向任何东西或手动删除指针.

In fact, let's act on on that final comment about std::unique_ptr right now. A unique_ptr manages your dynamic allocations for you so you don't have to clutter up your code with deletes and run the risk of missing one or deleteing too soon. The unique_ptr's pointer is valid for as long as the unique_ptr is in scope. If you can compile, the pointer is good unless you done something silly like never point it at anything or manually remove the pointer.

在我们讨论的同时,让我们消除我先前对vehicle::Create的担忧.

And while we're at it, let's eliminate my earlier concerns about vehicle::Create.

首先,我们定义一个自由函数来替换Create并返回一个unique_ptr.由于我讨厌必须在我的代码中全部检查if (ptr != NULL)以确保确实创建了对象,因此当我们无法通过抛出异常将提供的车辆类型与类匹配时,让我们对此大加恶心.

First we define a free function to replace Create and return a unique_ptr. Since I hate to have to have if (ptr != NULL) checks all through my code to make sure an object really was created, let's also make a big stink about it when we can't match the provided vehicle type with class by throwing an exception.

我们将使用一个更优雅的switch语句,而不是一个if-else if链.

And rather than a chain of if-else ifs we'll use a somewhat more elegant switch statement.

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

然后我们将使用此新功能

And then we'll use this new function

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原型和车辆类型列表的标题中,并隐藏其他所有内容.用户什么都看不到.每个人都处于黑暗中.

The beauty of this approach is no class knows anything about any other class. You can put Vehicle in a header with the SmarterVehicleFactory prototype and the list of vehicle types and hide everything else. The user sees nothing. Everybody is kept in the dark.

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

Why is that good? Because now you can change any of the above classes, except the Vehicle interface class, without having any effect on any of the other classes. This makes your code easier to maintain and debug.

这篇关于从基类指针调用派生类非虚拟成员函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆