Форум программистов, компьютерный форум CyberForum.ru

Виртуальная функция и возвращаемое значение - C++

Восстановить пароль Регистрация
 
Рики
6 / 6 / 1
Регистрация: 27.02.2013
Сообщений: 23
15.09.2013, 23:00     Виртуальная функция и возвращаемое значение #1
Этот код нужен для разбора арифметических выражений. Пишем что-то типа "1,456+654,5*65.45", после чего в стек помещаются числа типа float и операторы типа char. Для этого создан виртуальный класс "Token", наследниками которого являются Operator и Number. Программа служит для разбора строки, и подсчета результата.

Проблема с виртуальными функциями. VS 2012 выдает:
error LNK2001: неразрешенный внешний символ ""public: virtual char __thiscall Number::getOperator(void)" (?getOperator@Number@@UAEDXZ)"
error LNK2001: неразрешенный внешний символ ""public: virtual float __thiscall Operator::getNumber(void)" (?getNumber@Operator@@UAEMXZ)"
сокращенно код
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
// parse.cpp
#include <iostream>
#include <cstring>                   //for strlen(), etc
#include <stdlib.h> 
using namespace std;
const int LEN = 80;    //length of expressions, in characters
const int MAX = 40;    //size of stack
////////////////////////////////////////////////////////////////
  class Token                      // Абстрактный базовый класс
    {
    public:
      virtual void showOperNumber()=0; // чистая виртуальная
      virtual char getOperator()=0;             // функция
      virtual float getNumber()=0; 
 
      
    };
////////////////////////////////////////////////////////////////
  class Operator : public Token
    {
    private:
      char oper;             // Операторы +, –, *, /
    public:
      Operator(char c): oper(c)      // конструктор устанавливает значение
        {}
      void showOperNumber()    // получить значение
        {cout<<oper<<endl; }
      virtual float getNumber();
      char getOperator()
        {return oper;}
     
    };
////////////////////////////////////////////////////////////////
  class Number : public Token
    {
    private:
      float fnum;            // число
    public:
      Number(float f): fnum(f)         // конструктор устанавливает значение
         {}
      void showOperNumber()     // получить значение
        {cout<<fnum<<endl;}
      float getNumber()
        {return fnum;}
      virtual char getOperator();
    };
////////////////////////////////////////////////////////////////////
class Stack
   {
   private:
      Token* atoken[100];    //содержит типы Operator* и Number*                  
      int top;                       //number of top of stack
   public:
      Stack()                        //constructor
         { top = 0; }
      void push(Token* var)            //put char on stack
         { atoken[++top] = var; }
      Token* pop()                     //take char off stack
         { return atoken[top--]; }
      int gettop()                   //get top of stack
         { return top; }
   };
////////////////////////////////////////////////////////////////
int main()
   {
   setlocale (LC_ALL, "russian");
   Stack s;
   char stroka [LEN]="5,093+5,032";                          //char from input string
   char chifra [LEN];  
   char Ch;                     
   float n;
   float lastval;
   char lastop;
   //cout<<" Введите выражение. ";
   //cin>>stroka;
   int len = strlen(stroka);
   int j=0;
   int i=0; 
   Token* atoken[4] = {new Operator('+'), new Number(123.123),
                       new Operator('-'), new Number(456.456)};
   for(int k=0; k<4; k++)
        atoken[k]->showOperNumber();
 
   system("pause");
   return 0;
   }


Полностью:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// parse.cpp
#include <iostream>
#include <cstring>                   //for strlen(), etc
#include <stdlib.h> 
using namespace std;
const int LEN = 80;    //length of expressions, in characters
const int MAX = 40;    //size of stack
////////////////////////////////////////////////////////////////
  class Token                      // Абстрактный базовый класс
    {
    public:
      virtual void showOperNumber()=0; // чистая виртуальная
      virtual char getOperator()=0;             // функция
      virtual float getNumber()=0; 
 
      
    };
////////////////////////////////////////////////////////////////
  class Operator : public Token
    {
    private:
      char oper;             // Операторы +, –, *, /
    public:
      Operator(char c): oper(c)      // конструктор устанавливает значение
        {}
      void showOperNumber()    // получить значение
        {cout<<oper<<endl; }
      virtual float getNumber();
      char getOperator()
        {return oper;}
     
    };
////////////////////////////////////////////////////////////////
  class Number : public Token
    {
    private:
      float fnum;            // число
    public:
      Number(float f): fnum(f)         // конструктор устанавливает значение
         {}
      void showOperNumber()     // получить значение
        {cout<<fnum<<endl;}
      float getNumber()
        {return fnum;}
      virtual char getOperator();
    };
////////////////////////////////////////////////////////////////////
class Stack
   {
   private:
      Token* atoken[100];    //содержит типы Operator* и Number*                  
      int top;                       //number of top of stack
   public:
      Stack()                        //constructor
         { top = 0; }
      void push(Token* var)            //put char on stack
         { atoken[++top] = var; }
      Token* pop()                     //take char off stack
         { return atoken[top--]; }
      int gettop()                   //get top of stack
         { return top; }
   };
////////////////////////////////////////////////////////////////
int main()
   {
   setlocale (LC_ALL, "russian");
   Stack s;
   char stroka [LEN]="5,093+5,032";                          //char from input string
   char chifra [LEN];  
   char Ch;                     
   float n;
   float lastval;
   char lastop;
   //cout<<" Введите выражение. ";
   //cin>>stroka;
   int len = strlen(stroka);
   int j=0;
   int i=0; 
   Number* ptrN;
   Operator* ptrO;
   for(j; j<len; j++)          //for each input character
   {
        if (stroka[j]>='0' && stroka[j]<='9' || stroka[j]==',')
        {
            while (stroka[j]>='0' && stroka[j]<='9' || stroka[j]==',')
            {
                chifra [i]=stroka[j];
                j++; i++;
                n = atof(chifra); 
            }
            ptrN = new Number(n);
            s.push(ptrN);    
        }
        else
        if(stroka[j]=='+' || stroka[j]=='-' || stroka[j]=='*' || stroka[j]=='/')
        {
            Ch = stroka[j];
            if (s.gettop()==1)
            {
                ptrO = new Operator(Ch);
                s.push(ptrO);   
            }
            else
            {
                lastval=s.pop()->getNumber();
                lastop=s.pop()->getOperator();
                if( (stroka[j]=='*' || stroka[j]=='/') && (lastop=='+' || lastop=='-') )
                {
                    ptrO = new Operator(lastop);
                    s.push(ptrO);   
                    ptrN = new Number(lastval);
                    s.push(ptrN);   
               }
               else                     //in all other cases
               {
               switch(lastop)        //do last operation
                  {                  //push result on stack
                  case '+': ptrN = new Number(s.pop()->getNumber() + lastval); break;
                  case '-': ptrN = new Number(s.pop()->getNumber() - lastval); break;
                  case '*': ptrN = new Number(s.pop()->getNumber() * lastval); break;
                  case '/': ptrN = new Number(s.pop()->getNumber() / lastval); break;
                  default:  cout << "\nUnknown oper"; exit(1);
                  }  //end switch
               }  //end else, in all other cases
            ptrO = new Operator(stroka[j]);
            s.push(ptrO);              //put current op on stack
            }  //end else, not first operator
         }  //end else if, it's an operator
   
      else                           //not a known character
         { cout << "\nUnknown input character"; exit(1); }
   }
//--------------------------------------------------------------
 
    while(s.gettop() > 1)
      {
      lastval = s.pop()->getNumber();//get previous value
      switch( s.pop()->getOperator() )              //get previous operator
         {                           //do operation, push answer
         case '+': new Number(s.pop()->getNumber() + lastval); break;
         case '-': new Number(s.pop()->getNumber() - lastval); break;
         case '*': new Number(s.pop()->getNumber() * lastval); break;
         case '/': new Number(s.pop()->getNumber() / lastval); break;
         default:  cout << "\nUnknown operator"; exit(1);
         }  //end switch
      }  //end while
   s.pop()->showOperNumber();
   system("pause");
   return 0;
   }


как правильно описать ?
C++
1
virtual char getOperator()=0; virtual float getNumber()=0;
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
15.09.2013, 23:00     Виртуальная функция и возвращаемое значение
Посмотрите здесь:

возвращаемое значение функции C++
Возвращаемое значение функции C++
Возвращаемое значение C++
C++ Возвращаемое значение функции
Возвращаемое ссылочное значение C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
15.09.2013, 23:28     Виртуальная функция и возвращаемое значение #2
Рики, что бы собралось, можно сделать "пустую" реализацию.
C++
1
virtual float getNumber() { return 0; }
Но вообще плохой интерфейс.
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
15.09.2013, 23:30     Виртуальная функция и возвращаемое значение #3
Цитата Сообщение от Рики Посмотреть сообщение
Проблема с виртуальными функциями. VS 2012 выдает:
error LNK2001: неразрешенный внешний символ ""public: virtual char __thiscall Number::getOperator(void)" (?getOperator@Number@@UAEDXZ)"
error LNK2001: неразрешенный внешний символ ""public: virtual float __thiscall Operator::getNumber(void)" (?getNumber@Operator@@UAEMXZ)"
где реализации
Number::getOperator(void)
Operator::getNumber(void)
?
тело у них должно быть
Рики
6 / 6 / 1
Регистрация: 27.02.2013
Сообщений: 23
16.09.2013, 02:39  [ТС]     Виртуальная функция и возвращаемое значение #4
C++ (Qt)
1
virtual float getNumber() { return 0; }
Да, в упрощенном варианте работает, но в полной версии нет.
Наверное, нужно было только полный текст листинга приводить.

Но вообще плохой интерфейс.
Согласен, но лучше сначала запустить, а лоск и потом можно навести.

где реализации
Number::getOperator(void)
Operator::getNumber(void)
А что там прописывать? Если бы значение не возвращало, то можно было бы просто написать :
C++
1
 virtual void getNumberOperator();
а так, даже не знаю. Если из класса, например, "Operator" убрать "virtual float getNumber();", он становится абстрактным. Как можно решить эту проблему?
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
16.09.2013, 02:50     Виртуальная функция и возвращаемое значение #5
Цитата Сообщение от Рики Посмотреть сообщение
Если из класса, например, "Operator" убрать "virtual float getNumber();", он становится абстрактным. Как можно решить эту проблему?
Реализовать все виртуальные методы: getNumber - в Operator, getOperator - в Number.
Цитата Сообщение от Рики Посмотреть сообщение
Согласен, но лучше сначала запустить, а лоск и потом можно навести.
Просто если некоторые операции в наследниках не нужны, то не понятно, зачем тогда реализовывать этот интерфейс (здесь наследоваться от Token).
Рики
6 / 6 / 1
Регистрация: 27.02.2013
Сообщений: 23
16.09.2013, 02:59  [ТС]     Виртуальная функция и возвращаемое значение #6
Цитата Сообщение от gray_fox Посмотреть сообщение
Реализовать все виртуальные методы: getNumber - в Operator, getOperator - в Number.
Да, но как это грамотно сделать? Если прописать
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Operator : public Token
    {
    private:
      char oper;             // Операторы +, –, *, /
    public:
      Operator(char c): oper(c)      // конструктор устанавливает значение
        {}
      void showOperNumber()    // получить значение
        {cout<<oper<<endl; }
      virtual float getNumber()
        { return fnum; }
      char getOperator()
        {return oper;}
     
    };

в этом классе не будет "fnum".
gray_fox
What a waste!
 Аватар для gray_fox
1244 / 1127 / 53
Регистрация: 21.04.2012
Сообщений: 2,350
Завершенные тесты: 3
16.09.2013, 03:07     Виртуальная функция и возвращаемое значение #7
Цитата Сообщение от Рики Посмотреть сообщение
Да, но как это грамотно сделать?
Грамотно: нужен другой подход - дизайн, если хочешь.
Что бы скомпилировалось: поставить заглушку:
C++
1
virtual float getNumber() { return 0.f; }
Добавлено через 1 минуту
Цитата Сообщение от Рики Посмотреть сообщение
в этом классе не будет "fnum".
В том то и дело, зачем этот метод вообще нужен? Если ты реализуешь Token, значит он вроде как тебе нужен...
Рики
6 / 6 / 1
Регистрация: 27.02.2013
Сообщений: 23
16.09.2013, 03:44  [ТС]     Виртуальная функция и возвращаемое значение #8
Переделал.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// parse.cpp
#include <iostream>
#include <cstring>                   //for strlen(), etc
#include <stdlib.h> 
using namespace std;
const int LEN = 80;    //length of expressions, in characters
const int MAX = 40;    //size of stack
////////////////////////////////////////////////////////////////
  class Token                      // Абстрактный базовый класс
    {
    public:
      virtual void showOperNumber()=0; // чистая виртуальная
      virtual char getOperator()=0;             // функция
      virtual float getNumber()=0; 
 
      
    };
////////////////////////////////////////////////////////////////
  class Operator : public Token
    {
    private:
      char oper;             // Операторы +, –, *, /
    public:
      Operator(char c): oper(c)      // конструктор устанавливает значение
        {}
      void showOperNumber()    // получить значение
        {cout<<oper<<endl; }
      virtual float getNumber()
        { return 0.f; }
      char getOperator()
        {return oper;}
     
    };
////////////////////////////////////////////////////////////////
  class Number : public Token
    {
    private:
      float fnum;            // число
    public:
      Number(float f): fnum(f)         // конструктор устанавливает значение
         {}
      void showOperNumber()     // получить значение
        {cout<<fnum<<endl;}
      float getNumber()
        {return fnum;}
      virtual char getOperator()
        { return 0.f; }
    };
////////////////////////////////////////////////////////////////////
class Stack
   {
   private:
      Token* atoken[100];    //содержит типы Operator* и Number*                  
      int top;                       //number of top of stack
   public:
      Stack()                        //constructor
         { top = 0; }
      void push(Token* var)            //put char on stack
         { atoken[++top] = var; }
      Token* pop()                     //take char off stack
         { return atoken[top--]; }
      int gettop()                   //get top of stack
         { return top; }
   };
////////////////////////////////////////////////////////////////
class express
{
    private:
        Stack s;
        char* pStr;
        int len;
    public:
        express (char* ptr)
        {
            pStr=ptr;
            len =strlen(pStr);
        }
        void parse ();     // разбор выражения
        float solve ();      // получение результата
};
//--------------------------------------------------------------
void express::parse()
{
    char chifra [LEN];    //символы из строки
    float lastval;        // последнее значение
    char lastop;          // последний оператор
    Token* atoken[100];
    Number* ptrN;
    Operator* ptrO;
    float n;
    char Ch;  
    int j=0;
    int i=0; 
 
    for(j; j<len; j++)          //для всех символов в строке
    {
        if (pStr[j]>='0' && pStr[j]<='9' || pStr[j]==',')
        {
            while (pStr[j]>='0' && pStr[j]<='9' || pStr[j]==',')  // получаем число 
            {
                chifra [i]=pStr[j];
                j++; i++;
                n = atof(chifra); 
            }
            ptrN = new Number(n);
            s.push(ptrN);                                       // заносим  в стек
        }
        else
        if(pStr[j]=='+' || pStr[j]=='-' || pStr[j]=='*' || pStr[j]=='/')
        {
            Ch = pStr[j];
            if (s.gettop()==1)                                    // если это первый оператор, то помещаем в стек
            {
                ptrO = new Operator(Ch);
                s.push(ptrO);   
            }
            else
            {
                lastval=s.pop()->getNumber();                //получение предыдущего числа
                lastop=s.pop()->getOperator();              //получение предыдущего оператора
                // если это * или / , а предыдущий был + или -, то
                if( (pStr[j]=='*' || pStr[j]=='/') && (lastop=='+' || lastop=='-') )
                {
                    ptrO = new Operator(lastop);   //отменяем последние два взятия из стека
                    s.push(ptrO);   
                    ptrN = new Number(lastval);
                    s.push(ptrN);   
               }
               else                     //помещаем в стек текущий оператор 
               {
               switch(lastop)        
                  {                  
                  case '+': ptrN = new Number(s.pop()->getNumber() + lastval); break;
                  case '-': ptrN = new Number(s.pop()->getNumber() - lastval); break;
                  case '*': ptrN = new Number(s.pop()->getNumber() * lastval); break;
                  case '/': ptrN = new Number(s.pop()->getNumber() / lastval); break;
                  default:  cout << "\nUnknown oper"; exit(1);
                  }  
               }  
            ptrO = new Operator(pStr[j]);
            s.push(ptrO);              //помещаем в стек текущий оператор 
            }  
         }  
   
      else                           //что-то левое
         { cout << "\nUnknown input character"; exit(1); }
   }
}
//-------------------------------------------------------------
float express::solve ()  //убираем данные из стека
{
    float lastval;              
    while(s.gettop() > 1)
      {
      lastval = s.pop()->getNumber();               //предыдущее значение 
      switch( s.pop()->getOperator() )              //получение предыдущего оператора
         {                           //do operation, push answer
         case '+': new Number(s.pop()->getNumber() + lastval); break;
         case '-': new Number(s.pop()->getNumber() - lastval); break;
         case '*': new Number(s.pop()->getNumber() * lastval); break;
         case '/': new Number(s.pop()->getNumber() / lastval); break;
         default:  cout << "\nUnknown operator"; exit(1);
         }  
      }  
   return float (s.pop()->getNumber());//последний оператор в стеке это результат
}
////////////////////////////////////////////////////////////////
 
int main()
   {
   setlocale (LC_ALL, "russian");
   char stroka [LEN]="5,093+5,032";                         
   express* eptr = new express (stroka);
   eptr->parse();
   cout <<"\nРезультат: "
       << eptr->solve();
   delete eptr;
   system("pause");
   return 0;
   }

Результата нет.
Буду благодарен совет.

ps "0.f"- что это значит? как понять эту заглушку?
alex_x_x
бжни
 Аватар для alex_x_x
2441 / 1646 / 84
Регистрация: 14.05.2009
Сообщений: 7,163
16.09.2013, 04:00     Виртуальная функция и возвращаемое значение #9
Цитата Сообщение от Рики Посмотреть сообщение
ps "0.f"- что это значит? как понять эту заглушку?
0. - это валидное представление нуля с плавающей точкой (ровно как и .0)
f - literal suffix (уж не помню как это по-русски) для float, означает, что эта константа будет типа float
0. - будет double

http://www.cplusplus.com/doc/tutorial/constants/
Рики
6 / 6 / 1
Регистрация: 27.02.2013
Сообщений: 23
18.09.2013, 06:50  [ТС]     Виртуальная функция и возвращаемое значение #10
Спасибо за содействие. Запустил, все работает как надо.
Хотя, так и не разобрался с этими заглушками.
я поставил
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Number : public Token
    {
    private:
      float fnum;            // число
    public:
      Number(float f): fnum(f)         // конструктор устанавливает значение
         {}
      void showOperNumber()     // получить значение
        {cout<<fnum<<endl;}
      float getNumber()
        {return fnum;}
      virtual char getOperator()
        { return 0.f; }
    };

почему не выдавало ошибку в return 0.f; когда мы должны возвратить char?
И еще одно: что лучше писать в тех функциях, которые необходимо заполнить дабы порожденный класс не был виртуальным, а по факту эти функции в классе не нужны?
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
18.09.2013, 23:01     Виртуальная функция и возвращаемое значение #11
Цитата Сообщение от Рики Посмотреть сообщение
И еще одно: что лучше писать в тех функциях, которые необходимо заполнить дабы порожденный класс не был виртуальным, а по факту эти функции в классе не нужны?
бросить исключение
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
18.09.2013, 23:06     Виртуальная функция и возвращаемое значение
Еще ссылки по теме:

Шаблонная Функция: возвращаемое значение должно быть такого же типа, как входящее C++
C++ Значение, возвращаемое функцией (C++)
C++ Классы. Возвращаемое значение

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Tulosba
:)
Эксперт C++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
18.09.2013, 23:06     Виртуальная функция и возвращаемое значение #12
Цитата Сообщение от Рики Посмотреть сообщение
а по факту эти функции в классе не нужны
Скорее всего нужно пересмотреть иерархию.
Yandex
Объявления
18.09.2013, 23:06     Виртуальная функция и возвращаемое значение
Ответ Создать тему
Опции темы

Текущее время: 11:32. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru