多态性与DownCasting

Polymorphism vs DownCasting

本文关键字:DownCasting 多态性      更新时间:2023-10-16

假设我有一个基类Employee和一个派生类Manager,如下所示:

class Employee
{
public:
    string Name;  
};
class Manager : public Employee
{
public:
    string Designation;
};

在实现以下功能时:

Employee* SomeFunction(bool SomeCondition)
{
    Employee *Emp = NULL;
    if (SomeCondition) 
    {
       //Code goes here : Both Implementation 1 and 2 work fine!          
    }              
    return Emp;
}

SomeCondition为true时,我希望返回一个类型为Manager的非null对象。在这种情况下,以下两段代码似乎都符合要求:

实施1:

Manager *Mng = new Manager;
Mng->Name = "Adam";
Mng->Designation = "BOSS";
Emp = Mng;

实施2:

Emp = new Manager;
Manager *Mng = (Manager*)Emp;
Mng->Name = "Adam";
Mng->Designation = "BOSS";

既然两者都很好,我想知道两者中哪一个更有效?

哪一个在使用多态性的概念?

实现2中的类型转换是向下转换吗?这是好的做法吗?

虽然我看到了你的问题背后的一些原因,但我认为你需要改进您的示例

  • 你是说你需要返回一个非null对象类型为"Manager",而您定义的是"SomeFunction(bool-SomeCondition("返回"雇员"。

  • 如果你真的要返回"Employee"对象,为什么要麻烦初始化"指定",而您将无法访问它后来例如:

    cout << SomeFunction(true)->Designation(); // error !  
    

所以,我不知道说你的例子很好是什么意思,因为上下文不清楚。

**比较实施1和2/关于动态铸造

虽然这两个例子都可以改进,但我认为Implementation 1较好的在这两种情况下,都执行动态铸造。但是,在实施过程中1,您在"Emp=Mng;"中进行了隐式上转换,而在实现2中您在"ManagerMng=(Manager(Emp;"中执行下转换。

一般来说,你应该避免投射(尤其是向下投射,因为它与upcasting相比,不是一直都那么安全(,如果必须的话您应该使用C++样式的强制转换(例如dynamic_cast(。请参阅中的示例https://www.tutorialcup.com/cplusplus/upcasting-downcasting.htm

更好的解决方案是使用虚拟函数来避免铸造并腾出空间在"管理器"旁边添加更多对象类型。例如,您的标题可能看起来像:

class Employee
{
  public:
    virtual void setDesignation(const string & d) = 0;
    virtual string getDesignation() = 0; 
};
class Manager : public Employee
{
  public:
    virtual void setDesignation (const string & d) {Designation=d;}
    virtual string getDesignation() {return Designation;}
  private:
    string Designation;
};

你的功能可能看起来像:

Employee* SomeFunction(bool SomeCondition)
{
   Employee *Emp = NULL;
   if (SomeCondition) 
   {
     Emp = new Manager;;
     Emp->setDesignation("BOSS");             
   }              
   return Emp;
}

如果你想稍后访问指定,你可以进行

cout << SomeFunction(true)->getDesignation();

**关于多态性

在这两个例子中都没有使用任何多态性。这是因为你没有使用任何特定于类型的函数,这样您的运行时行为就不会根据"Employee"对象的不同而有所不同(您仅使用一种对象类型"经理"!(。请参阅中的示例http://www.tutorialspoint.com/cplusplus/cpp_polymorphism.htm

您的两个实现都按照您的意愿进行,但是第二个实现是非常的糟糕做法。

首先,让我们澄清一下你似乎有一个误解:在你的第二个实现中,你没有做通常被认为是沮丧的事情。您正在使用C样式的强制转换(请参阅http://en.cppreference.com/w/cpp/language/explicit_cast),在丢弃诸如const之类的东西中,它将愉快地将任何指针丢弃到Manager*。例如,你还不如做

Manager *Mng = (Manager*) new Employee; // not a good idea

甚至

Manager *Mng = (Manager*) new int; // now, this is really bad...

一般来说,您不应该在C++中使用C样式强制转换。


您可以使用dynamic_cast:在C++中进行安全的下变频

Manager *Mng = dynamic_cast<Manager*>(ptr_to_manager);  // will return a pointer to the Manager object
Manager *Mng = dynamic_cast<Manager*>(ptr_to_employee); // will return nullptr

尽管如此,检查您的强制转换是否真的安全还是需要运行时开销(即,区分示例中的第一种情况和第二种情况(。顺便说一句,对下变频的需求通常表明设计不好。


简言之,第一个实现是更容易、更明显的方法:不需要向下转换、安全或不安全。