C ++将基类型传递给纯虚函数

时间:2015-01-05 21:37:15

标签: c++ abstract-class virtual

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

澄清这个问题,我从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 */ }
};

}

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

4 个答案:

答案 0 :(得分:1)

您应该像这样构建代码:

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参数传递。不幸的是,当需要多个参数时,这在复杂情况下不起作用。但是,这就是语言设计者的想法。还没有开发出完美的语言。

答案 1 :(得分:1)

您正在使用错误的类来获取虚函数的概念。类“知道”它是什么(通过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();   */

答案 2 :(得分:1)

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

另一种方法是使用访客模式: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 ++时,尽量避免虚函数:)并将所有内容移到静态多态::)

答案 3 :(得分:0)

我认为你不能和他们想要的行为。

执行此操作的唯一方法是为您抛出参数(由于您有四种不同的类型,因此在C ++中非常复杂)。其他解决方案是向任何员工提供成绩属性。

亚历。