вызов правильной формы полиморфной функции. С++

У меня проблемы с поиском способа вызвать правильную форму полиморфной функции без редактирования функции int main().

void Print(Operator*  someOp); //function definition

int main(int argc, char* const argv[])
{
Operator* ptr = NULL;

...
... //this is the body


void Print(Operator*  someOp)
 // Writes description of card to stdout
 {
    someOp->WriteOperator();         // Hint:  Polymorphic function
 }

}

Я сделал основную функцию как можно более краткой выше, но вся функция находится внизу для любой справки.

Итак, есть класс операторов, в котором есть функция с именем void WriteOutput(), но затем UnaryOp наследуется от Operator, а также имеет другую функцию void WriteOutput().

но они выводят разные данные. поэтому мой вопрос в том, как я могу сделать основной вызов правильной функцией. Я знаю, что если бы я мог редактировать main, я мог бы просто установить для someOp любой класс, который я хотел бы вызвать, но я не могу редактировать main. единственные файлы, которые я могу редактировать, это operator.h и UnaryOp.cpp. В программе есть еще файлы, но все они имеют одну и ту же проблему с вызовом функции, поэтому, если я смогу исправить это, остальное будет легко.

// main.cpp
//
// Driver program for Card program which is used to test each
// class member function.
//
// DO NOT MODIFY OR SUBMIT THIS FILE
//

// List of allowed include files appear below
#include <iostream>
#include <fstream>
#include <string>
#include "operator.h"
#include "unaryop.h"
#include "binaryop.h"
#include "factorial.h"
#include "plus.h"
#include "minus.h"
#include "times.h"
#include "slash.h"


using namespace std;                     // Global using declaration

void Bar();                              // Prototype for Bar function
void Print(Operator*  someOp);           // Prototype for Print function



// Start of main() function


int main (int argc, char* const argv[])  // Command-line arguments (more on this later)
{
ifstream inputs;       // Input file stream variable    for test file
char op, ch;     // Hold operation and optional char input from test file
string   comment;                      // Holds comment string input from test file
Operator* ptr = NULL;                  // Pointer to abstract operator object
int      operand1,operand2;            // Holds operand values input from test file


 // Output usage message if test input file name is not provided
 if (argc != 2)
  {
   cout << "Usage:\n  project02  <inputfile>\n";
    return 1;
  }

  // Attempt to open test input file -- terminate if file does not open
  inputs.open(argv[1]);
  if (!inputs)
  {
    cout << "Error - unable to open input file" << endl;
    return 1;
  }

  Bar();

  // Process comment line from input file
  getline(inputs, comment);                          // Input file header comment
  cout << endl << comment << endl << endl;           // Output file header comment


  // Below is the primary loop that processes each operation appearing within the test   file.
  // Starts with an initial priming read of first operation

  inputs >> op;                                      // Attempt to input     first test operation from file

  while (inputs)                                     // While Not-EOF
  {
    switch (op)                                      // Process operation input from test file
    {
     case '#':   // Test file comment
            getline(inputs, comment);      // Input and echo the comment appearing in the    test file
            cout << '#' << comment << endl;
            break;

     case 'p':   // Print Operator 
            Print(ptr);
            break;  

     case '~':   // Print Bar
            Bar();                         // Function definition appears at the end of     this file
            break;              

     case 'o':   // Set output to desired value
                 inputs >> operand1;
                 ptr->SetOutput(operand1);
                 break;

     case 's':   // Set symbol to desired value
                 inputs >> ch;
                 ptr->SetSymbol(ch);
                 break;

     case ';':   // Reset operand one and trigger output update
                 inputs >> operand1;
                 {
                   UnaryOp* temp = (UnaryOp*) ptr;    // Treat as a unary operator pointer
                   temp->SetOperand(operand1);
                 }
                 break;

     case ':':   // Reset both operands and trigger output update
                 inputs >> operand1 >> operand2;
                 {
                   BinaryOp* temp = (BinaryOp*) ptr;  // Treat as a binary operator pointer
                   temp->SetOperand1(operand1);       
                   temp->SetOperand2(operand2);
                 }
                 break;

     case 'c':   // Use symbol input from file to invoke appropriate constructor
                 inputs >> op;              // Input symbol
                 try
                 {
                   cout << "Constructor -- ";
                   switch (op)
                   {
                     case '?':  // Operator
                                ptr = new Operator;
                                break;
                     case 'u':  // UnaryOp
                                inputs >> operand1;
                                ptr = new UnaryOp(operand1);
                                break;
                     case '!':  // Factorial
                                inputs >> operand1;
                                ptr = new Factorial(operand1);
                                break;
                     case 'b':  // BinaryOp
                                inputs >> operand1 >> operand2;
                                ptr = new BinaryOp(operand1, operand2);
                                break;
                     case '+':  // Plus
                                inputs >> operand1 >> operand2;
                                ptr = new Plus(operand1, operand2);
                                break;
                     case '-':  // Minus
                                inputs >> operand1 >> operand2;
                                ptr = new Minus(operand1, operand2);
                                break;
                     case '*':  // Times
                                inputs >> operand1 >> operand2;
                                ptr = new Times(operand1, operand2);
                                break;
                     case '/':  // Slash
                                inputs >> operand1 >> operand2;
                                ptr = new Slash(operand1, operand2);
                                break;
                     default:   cout << "Error: unrecognized object" << endl;
                    } // End switch (op)


                    cout << "Successful"; 
                  }  // End try
                  catch ( ... )                // Catch any exception thrown above
                  { 
                    cout << "Failed";  
                  }

                  cout << endl;                  
                      break;

      case 'd':   // Destructor
                  try
                  {
                    cout << "Destructor -- ";
                    delete ptr;                        // Deallocate card 
                   cout << "Successful";
                   ptr = NULL;                        // Make sure that ptr is not a dangling pointer
              }
              catch ( ... )
              {
                cout << "Failed";
              }
              cout << endl;
              break;        

  default:    // Error
              cout << "Error - unrecognized operation '" << op << "'" << endl;
              cout << "Terminating now..." << endl;
                  return 1;
              break;
}

inputs >> op;                                    // Attempt to input next command
  }

  cout << endl;

  return 0;
}

/************** Implementation of Print() and Bar() functions ********************/

// DO NOT MODIFY THIS CODE

void Bar()
// Bar() -- prints horizontal bar
    {
    cout << "#################################################################" << endl;
    }  // End Bar()


void Print(Operator*  someOp)
// Writes description of card to stdout
{
    someOp->WriteOperator();         // Hint:  Polymorphic function
}

/**************  End of main.cpp  ***************/

person oscar tapia    schedule 13.09.2011    source источник
comment
Вы объявили WriteOperator как virtual?   -  person Oliver Charlesworth    schedule 14.09.2011
comment
@Oli Charlesworth: он говорит, что функции выводят разные данные, поэтому ему не следует использовать виртуальное наследование.   -  person K-ballo    schedule 14.09.2011
comment
Ага, понятно. Вы просто используете ptr, например. UnaryOp *. Что ж, это не сработает, если только ptr на самом деле не указывает на объект UnaryOp.   -  person Oliver Charlesworth    schedule 14.09.2011
comment
@K-ballo: я не говорю о виртуальном наследовании.   -  person Oliver Charlesworth    schedule 14.09.2011


Ответы (1)


Прелесть полиморфизма в C++ заключается в том, что он всегда вызывает правильный метод. Вероятно, вы забыли сделать WriteOperator() virtual. Это синтаксис для переопределения поведения родителя. Таким образом, вы можете сохранить указатель типа базового класса, указать его на любой дочерний объект и вызвать правильный метод без приведения (в конце концов, UnaryOp является Operator). Это работает при условии, что реальный тип базового объекта является типом дочернего объекта.

Внутри вашего файла Operator.cpp это может выглядеть примерно так:

void Operator::WriteOperator() 
{
    ...
}

И в заголовке:

virtual void WriteOperator();
person Chad La Guardia    schedule 13.09.2011
comment
У вас не будет Operator:: внутри тела класса. - person Oliver Charlesworth; 14.09.2011
comment
ах да ... это плохой копипаст. Хороший улов :Р - person Chad La Guardia; 14.09.2011
comment
АААА! Я понял. Вот чего мне не хватало виртуального void WriteOperator(); в заголовочном файле. У меня был только void WriteOperator(); Спасибо, я бы, наверное, все еще застрял, если бы не эта помощь. :) - person oscar tapia; 14.09.2011