LINUX.ORG.RU

Какая-то фигня с виртуальными методами

 , ,


0

1

Всем привет, у меня проблема с компиляцией плюсов. Ниже код и инофрмация об ошибке. Подскажите в чем проблема. Кроме того я нуб в ООП в плюсах, так что если что-то здесь можно переписать идеологически правильнее, скажите и об этом. lex.cpp:

#include "lex.h"
#include <cstring>
#include <list>

struct Ans {
	bool fin;
	bool err;
	int state;
};

static inline Ans newAns(bool f, int s){
	Ans a;
	a.fin = f;
	a.err = 0;
	a.state = s;
	return a;
}

static inline Ans newErr(){
	Ans a;
	a.fin = 0;
	a.err = 1;
	a.state = 0;
	return a;
}

#define ISLITS(c) (c >= 'a' && c <= 'z')
#define ISLITB(c) (c >= 'A' && c <= 'Z')
#define ISNUM(c)  (c >= '0' && c <= '9')

class Automat {
	protected:
		virtual Ans nextSymbol(char c);
	public:
		int len = 0;
		int ltype = L_NONE;
		int state = 0;
		bool fin = 0;
		bool err = 0;
		std::string text;
		bool next(char c){
			Ans a = this -> nextSymbol(c);
			this -> err = a.err;
			if (! this -> err) {
				this -> fin = a.fin;
				this -> state = a.state;
				this -> len ++;
				this -> text += c;
			}
			return ! a.err;
		}
};

class Aint : public virtual Automat {
	protected:
		virtual Ans nextSymbol(char c){
			if (c >= '0' && c <= '9')
				return newAns(1,0);
			return newErr();
		}
	public:
		Aint(){
			this -> ltype = L_INT;
		}
};

class Areal : public Automat {
	protected:
		virtual Ans nextSymbol(char c){
			switch(this -> state){
				case 0:
					if (ISNUM(c))
						return newAns(0,1);
					return newErr();
				case 1:
					if (ISNUM(c))
						return newAns(0,1);
					if (c == '.')
						return newAns(0,2);
					return newErr();
				case 2:
					if (ISNUM(c))
						return newAns(1,2);
					return newErr();
				default:
					return newErr();
			}
		}
	public:
		Areal(){
			this -> ltype = L_REAL;
		}
};

class Astr : public Automat {
	protected:
		virtual Ans nextSymbol(char c){
			switch(this -> state){
				case 0:
					if (c == '"')
						return newAns(0,1);
					return newErr();
				case 1:
					if (c == '"')
						return newAns(1,2);
					return newAns(0,1);
				default:
					return newErr();
			}
		}
	public:
		Astr(){
			this -> ltype = L_STR;
		}
};

class Aid : public Automat {
	protected:
		virtual Ans nextSymbol(char c){
			switch(this -> state){
				case 0:
					if (ISLITS(c) || ISLITB(c) || c == '_')
						return newAns(1,1);
					return newErr();
				case 1:
					if (ISLITS(c) || ISLITB(c) || ISNUM(c) || c == '_')
						return newAns(1,1);
					return newErr();
				default:
					return newErr();
			}
		}
	public:
		Aid(){
			this -> ltype = L_ID;
		}
};

class Abr : public Automat {
	protected:
		virtual Ans nextSymbol(char c){
			static const char brackets[] = "()[]{};.,";
			static int len = 0;
			if (len == 0)
				len = strlen(brackets);
			if (this -> state == 0){
				for(int i=0; i<len; ++i)
					if(brackets[i] == c)
						return newAns(1,1);
			}
			return newErr();
		}
	public:
		Abr(){
			this -> ltype = L_BR;
		}
};

class Aop : public Automat {
	protected:
		virtual Ans nextSymbol(char c){
			static const char symbols[] = "+-*/%^&|<>=!\\:#@";
			static int len = 0;
			if (len == 0)
				len = strlen(symbols);
			for(int i=0; i<len; ++i){
				if(symbols[i] == c)
					return newAns(1,1);
			}
			return newErr();
		}
	public:
		Aop(){
			this -> ltype = L_OP;
		}
};

using namespace std;

static int skipSpaces(string& str, int pos){
	for(;pos < str.length(); ++pos){
		char c = str[pos];
		if(c != ' ' && c != '\n' && c != '\r' && c != '\t')
			return pos;
	}
	return pos;
}

// is success new str pos will be written to 'spos'
bool lex(string& src, int& spos, string& dst, int& ltype){
	// skip space
	int pos = skipSpaces(src,spos);
	// init alist
	list<Automat> alist;
	alist.push_back(Aint());
	alist.push_back(Areal());
	alist.push_back(Astr());
	alist.push_back(Aop());
	alist.push_back(Abr());
	alist.push_back(Aid());
	alist.push_back(Aint());
	// search
	for(;pos < src.length(); pos++){
		bool flag = 0;
		for(auto& atm : alist)
			flag = flag || atm.next(src[pos]);
		if(flag)
			alist.remove_if([](Automat& atm){return atm.err;});
		else
			break;
	}
	// finalize
	for(auto& atm : alist){
		if(atm.fin){
			dst = atm.text;
			ltype = atm.ltype;
			spos = pos;
			return true;
		}
	}
	// if err
	return false;
}
main.cpp:
#include "lex.h"
#include <iostream>

using namespace std;

int main(){
	string text = "\thello world  12 g1 42 \n 12.2 \"dd\" += () 4";
	string dst;
	int ltype;
	int pos = 0;
	while(lex(text,pos,dst,ltype)){
		cout << "'" << dst << "' " << ltype << "\n";
	}
	cout << "end\n";
	return 0;
}
собираю так
g++ -c -std=c++0x -O2 lex.cpp
g++ -c -std=c++0x -O2 main.cpp
g++ -std=c++0x -o main -O2 lex.o main.o
Undefined symbols for architecture x86_64:
  "typeinfo for Automat", referenced from:
      typeinfo for Aid in lex.o
      typeinfo for Abr in lex.o
      typeinfo for Aop in lex.o
      typeinfo for Astr in lex.o
      typeinfo for Areal in lex.o
      typeinfo for Aint in lex.o
  "vtable for Automat", referenced from:
      lex(std::string&, int&, std::string&, int&) in lex.o
      std::list<Automat, std::allocator<Automat> >::_M_create_node(Automat const&) in lex.o
  NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

★★★★★

Стесняюсь спросить, что такое Automat?

Назови уж нормально.

chkalov ()
Ответ на: комментарий от chkalov

Это детерминированный конечный автомат.

Aswed ★★★★★ ()

NOTE: a missing vtable usually means the first non-inline virtual member function has no definition.

Видимо дело в том что нет реализации для функи Automat::nextSymbol, либо добавь реализацию, либо сделай её чисто виртуальной.

Ещё один косячище - у тебя в базовом классе деструктор, не виртуальный.

batbko ()

Где определение virtual Ans nextSymbol(char c); в Automat? Или тогда уже virtual Ans nextSymbol(char c) = 0;

А еще хорошо бы в Automat виртуальный деструктор забабахать, так на всякий пожарный.

vega ()
Ответ на: комментарий от batbko

Мне нужно, чтоб nextSymbol была чисто виртуальной. Как это указать?

Aswed ★★★★★ ()
Ответ на: комментарий от vega

А зачем он тут собственно нужен, если у потомков нет указателей на что-либо?

Aswed ★★★★★ ()
Ответ на: комментарий от Aswed
struct Foo {

}

struct Bar : public Foo {
    int a;
};

int main()
{
    Foo* bar = new Bar();
    delete bar;// UB here
    return 0;
}

Если в наследниках вообще нет данных, то формально не нужен. Но ты, как автор, в общем случае, не можешь гарантировать, что никто от него не отнаследуется с соблюдением этого ограничения. Более того, ты ничего не переплачиваешь, раз у тебя уже есть виртуальный метод. Как то так.

batbko ()
Ответ на: комментарий от Aswed

Когда делаешь базовый класс, никогда не знаешь кто и как будет его наследовать. Чтобы спасти время от туевой хучи дебага, лучше сразу его добавить.

vega ()

Всем привет, у меня проблема с компиляцией плюсов.

Звучит как утренне приветствие на радио.

с++

Беги, глупец. Беги пока не поздно.

nanoolinux ★★★★ ()

this ->

тяжелое наследие java ?

anonymous ()
Ответ на: комментарий от chkalov

Да, это дискретная математика. Но я вот Clang не пользуюсь и его вывод ошибок меня пугает.

golodranez ★★★★ ()
Ответ на: комментарий от golodranez

У гцц с этим тоже не все гладко. Порой из-за ошибки типизации где-нибудь в шаблоне огромные простыни выдает.

Aswed ★★★★★ ()

Я считал, что довольно неплохо владею C++, но понятия не имею, что делает static для функций.

hlebushek ()
Ответ на: комментарий от hlebushek

В терминах высокоуровневых ЯП, статическая функция - та, которую не экспортирует модуль.

Aswed ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.