【问题标题】:C++ passing base type to pure virtual functionC++ 将基类型传递给纯虚函数
【发布时间】:2015-01-05 21:37:14
【问题描述】:

我想了解派生类中纯虚函数在传递与(抽象)基类相同类型的参数时的行为。

为了澄清这个问题,我从 GeeksForGeeks 获取了以下代码并对其进行了修改:

namespace example {
enum Type {ENGINEER, MANAGER};
class Employee
{
private:    
    const Type worker;
public:
    Employee(const Type& worker) : worker(worker) {}
    virtual ~Employee {}

    virtual void raiseSalary(const Employee&) = 0;
    {  /* common raise salary code */  }

    virtual void promote(const Employee&) = 0;
    { /* common promote code */ }
};

class Manager: public Employee {
    private:
        int degree;
    public:
        //<constructor>\\

    virtual void raiseSalary(const Employee&)
    {  /* Manager specific raise salary code, may contain
          increment of manager specific incentives*/  }

    virtual void promote(const Employee&)
    { /* Manager specific promote */ }
};

}

现在,我们如何访问派生类Manager 中的字段degree 以更新他的degree?因为传递给raiseSalary(Employee&amp; employee) 的参数可能是ManagerEngineer

【问题讨论】:

  • 使用static_cast 可能建议使用switchif statments。我正在寻找一种利用 OOP 功能的方法。有没有办法克服这个问题?
  • 您的设计可能有缺陷。在这种情况下,将学位作为员工的一部分可能有意义吗?
  • 如果不是基类的属性,则不能修改该属性...
  • 但是说不同类型的工人有不同的私有字段。将它们添加到 Employee 是很痛苦的。
  • 为什么要将员工传递给非静态方法?

标签: c++ abstract-class virtual


【解决方案1】:

我认为有两种方法可以解决这个问题。让我们从一些非常糟糕的解决方案开始:使用强制转换。在那种情况下dynamic_cast。您可以尝试向下转换类型。如果dynamic_cast 无法做到这一点,它将返回一个空指针或抛出异常(取决于您是否转换了指针或值/引用类型)。但这种方法将迫使你调整你的演员阵容,因为更多的经理、工程师类型将会出现。您可能还需要使用friend 来允许特定类访问其他类的内部。 friend 不会在层次结构中被继承,所以你最终会有很多朋友 => 破碎,破碎,破碎 :(

另一种方法是使用访问者模式:http://en.wikipedia.org/wiki/Visitor_pattern 使用访问者模式,您还可以创建基本无操作访问者和更细粒度的访问者来处理特定内容。只是一个小例子(特定访问者没有派生):

namespace example {

  class SalaryRaisingVisitor;
  class EmployeePromotingVisitor;

  class Employee
  {
  public:
      Employee() {}
      //don't forget to implement the copy constructor: read more about rule of 3!!!

      virtual ~Employee {}

      virtual void accept(SalaryRaisingVisitor const&) = 0;
      virtual void accept(EmployeePromotingVisitor const&) = 0;
  };

  class Manager: public Employee {
      private:
          int degree;
      public:
          //<constructorS>

      virtual void accept(SalaryRaisingVisitor const& v)
      {
        v.visit(*this, degree); 
      }

      virtual void accept(EmployeePromotingVisitor const& v)
      {
        v.visit(*this, degree);
      }
  };

  class Engineer: public Employee {
      public:
          //<constructorS>

      virtual void accept(SalaryRaisingVisitor const& v)
      {
        v.visit(*this); 
      }

      virtual void accept(EmployeePromotingVisitor const& v)
      {
        v.visit(*this);
      }
  };

  class SalaryRaisingVisitor
  {
    void visit(Manager& m, int& degree) //might be const if no internal state changes
    {
      //...
    }

    void visit(Engineer& e) //might be const if no internal state changes
    {
      //...
    }
  };

}

在处理 C++ 的最后,尽量避免使用虚函数 :) 并将所有内容都转移到静态多态 :)

【讨论】:

    【解决方案2】:

    您对带有类的虚函数的概念有误解。类“知道”它是什么(通过 vtable),所以你可以把它写成类函数,而不是静态全局函数。类中的每个函数都知道所有类变量,因此您不必传递类的对象。

    namespace example {
    enum Type {ENGINEER, MANAGER};
    class Employee
    {
    private:    
        const Type worker;
    public:
        Employee(const Type& worker) : worker(worker) {}
        virtual ~Employee {}
    
        virtual void raiseSalary() = 0;
        {  /* common raise salary code */  }
    
        virtual void promote() = 0;
        { /* common promote code */ }
    };
    
    class Manager: public Employee {
        private:
            int degree;
        public:
            //<constructor>\\
    
        virtual void raiseSalary()
        {
        //the Employed standard code
        Employee::raiseSalary(); //This won't compile since you set the virtual function = 0
    
        //Manager specific raise salary code
        degree = 0; //this lazy bastards should do real work like coding stuff
    
    
        }
    
        virtual void promote()
        { 
    
        Employee::promote(); //employee common code. This won't compile since you set the virtual function = 0
        /* Manager specific promote */ 
        degree = degree * 2;
        }
    };
    
    Employee array[10];
    array[0] = Manager(); //create a manager object on the stack
    array[1] = Manager(); //create a manager object on the stack
    array[0].raiseSalary();  //Only Mananer0 gets raiseSalary
    /*the manager object in array[0] uses its virtual function 
    to the manager raiseSalary function. The Manager RaiseSalary function
    in this case calls the base class raiseSalary function explicitly 
    via Employee::raiseSalary();   */
    

    【讨论】:

      【解决方案3】:

      你应该像这样构造你的代码:

      class Employee
      {
          virtual void raiseSalary() = 0;
          virtual void promote() = 0;
      };
      
      class Manager: public Employee
      {    
          virtual void raiseSalary()
          {  /* Manager specific raise salary code, may contain... */ }
      
          virtual void promote()
          { /* Manager specific promote */ }
      };
      
      int main()
      {
          Manager bob;
          bob.promote();    // <--- Proper method in the Manager class will be called.
                            // Current instance will always have the right class.
      }
      

      换句话说,您应该寻找机会将特定派生类作为this 参数传递。不幸的是,这在需要多个参数的复杂情况下不起作用。但是,这是语言设计者的想法。完美的语言还没有开发出来。

      【讨论】:

        【解决方案4】:

        我认为你不能,这是想要的行为。

        做到这一点的唯一方法是强制转换参数(这在 C++ 中相当复杂,因为您有四种不同类型的强制转换)。其他解决方案是给任何员工一个等级属性。

        亚历克西斯。

        【讨论】:

        • 你是对的,你可以 static_cast 对象,但我不认为这是他想要的。他可能只是想要修改“this”对象的函数。
        猜你喜欢
        • 2018-02-15
        • 1970-01-01
        • 1970-01-01
        • 2014-04-03
        • 2014-12-25
        • 1970-01-01
        • 2018-04-10
        • 2015-08-20
        • 2022-01-13
        相关资源
        最近更新 更多