Second Opinion
Folosind serviciul second opinion ne puteți trimite RMN-uri, CT -uri, angiografii, fișiere .pdf, documente medicale. Astfel vă vom putea da o opinie neurochirurgicală, fără ca aceasta să poată înlocui un consult de specialitate. Răspunsurile vor fi date prin e-mail în cel mai scurt timp posibil (de obicei în mai putin de 24 de ore, dar nu mai mult de 48 de ore). Second opinion – Neurohope este un serviciu gratuit. www.neurohope.ro |
[C++] error LNK2001: unresolved external symbol "public: static struct Vector<class Variable> Symbol_table::names"
Last Updated: Sep 18 2018 17:30, Started by
AnduIX
, Sep 15 2018 10:44
·
0
#1
Posted 15 September 2018 - 10:44
Salut!
Ma aflu la capitolul VII din "Programming: Principles and Practice using C++". Lucrez la un calculator ce se descurca cu adunari, scaderi, inmultiri, impartiri, impartiri cu rest, ridicari la putere, radical, folosirea parantezelor, crearea si editarea unor variabile si crearea unor constante de catre utilizator. Sunt la un exercitiu ce spune urmatorul lucru: Quote
4. The get_value(), set_value(), is_declared(), and define_name() functions all operate on the variable var_table. Define a class called Symbol_table with a member var_table of type vector<Variable> and member functions get(), set(), is_declared(), and declare(). Rewrite the calculator to use a variable of type Symbol_table. Deocamdata sunt la partea dinainte de "Rewrite the calculator to use a variable of type Symbol_table.". Asadar, am creat o clasa Symbol_table in care am inclus toate acele functii (care folosesc names - vectorul in care se salveaza variabilele) si names. In loc de identificatorul var_tables, am folosit identificatorul names. Initial, n-am introdus static inainte de fiecare functie, insa pentru a putea folosi functia in mod independent, am aflat ca am nevoie de acel static. Cu ocazia asta am aflat un lucru nou. Problema este ca primesc eroarea Quote
error LNK2001: unresolved external symbol "public: static struct Vector<class Variable> Symbol_table::names" (?names@Symbol_table@@2U?$Vector@VVariable@@@@A) Am schimbat linia static vector<Variable> var_table;in static vector<Variable> Symbol_table::var_table;gandindu-ma ca rezolvarea este chiar in textul erorii, insa nu a functionat. Va rog frumos sa ma ajutati. Daca aveti nevoie de mai multe informatii, va rog sa imi spuneti. Fiecare linie de cod este comentata pentru a elimina o parte din eventualele intrebari referitoare la ceea ce face o anumita bucata de cod, intrucat nu am inclus definitiile functiilor membre ale clasei. Multumesc! class Variable { public: string name; // numele double value; // valoarea bool var; // este o variabila sau constanta? Variable(string n, double v, bool va) :name(n), value(v), var(va) { } }; class Symbol_table { public: static double get(string s); // returneaza valoarea variabilei / constantei cu nume s static void set(string s, double d); // seteaza valoarea d variabilei / constantei cu nume s static bool is_declared(string s); // exista deja o variabila / constanta cu nume s? static void predefine_name(string s, double d, bool var); // adauga noua variabila / constanta cu nume s si valoare d la vectorul names static vector<Variable> names; // vector de variabile si constante }; Edited by AnduIX, 15 September 2018 - 11:07. |
#2
Posted 15 September 2018 - 10:56
Arata tot codul. Eroarea mentioneaza "names" pe care nu-l vad in ce ai postat.
Apoi, fereste-te cat poti de static. |
#3
Posted 15 September 2018 - 11:12
dani.user, on 15 septembrie 2018 - 10:56, said:
Arata tot codul. Eroarea mentioneaza "names" pe care nu-l vad in ce ai postat. Apoi, fereste-te cat poti de static. Scuze! Acel "names" este, de fapt, "var_tables". In enunt precizeaza ca vectorul se numeste "var_tables", insa eu l-am numit "names" in cod. Am editat postarea initiala pentru a elimina aceasta confuzie. Codul complet (comentat in engleza, deoarece am avut un exercitiu care cerea comentarea intregului cod, acolo unde este nevoie), numai ca layout-ul nu s-a pastrat in urma procesului de copy - paste din Visual Studio in browser: #include "pch.h" #include "D:\Programming\Additionals\std_lib_facilities.h" const char let = 'L'; // declaration Token kind const char quit = 'Q'; const char print = ';'; const char number = '8'; const char name = 'a'; // name Token kind const char squareroot = 's'; // square root Token kind const char power = 'p'; // pow Token kind const char con = 'C'; // const declaration Token kind const string declkey = "#"; // declaration keyword Token kind const string quitkey = "exit"; const string constkey = "const"; // const declaration keyword Token kind class Token { public: char kind; double value; string name; Token(char ch) :kind{ ch }, value{ 0 } { } Token(char ch, double val) :kind{ ch }, value{ val } { } Token(char ch, string str) :kind{ ch }, name{ str } { } }; class Token_stream { public: Token_stream() :full{ 0 }, buffer{ 0 } { } // Token_stream that reads from cin Token get(); // gets a Token void unget(Token t) { buffer = t; full = true; } // puts a Token back void ignore(char c); // discards Tokens up to and including c private: bool full; // is there a Token in the buffer? Token buffer; // holds a Token put back by unget() }; Token Token_stream::get() // reads characters from cin and composes a Token { if (full) { full = false; return buffer; } // checks if there's a Token in the buffer char ch; cin >> ch; switch (ch) { case '(': case ')': case '+': case '-': case '*': case '/': case '%': case '=': case ',': case print: return Token(ch); // each character represents itself case '.': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { cin.unget(); double val; cin >> val; return Token(number, val); } default: if (isalpha(ch) || ch == '#') { // starts with a letter string s; s += ch; while (cin.get(ch) && (isalpha(ch) || isdigit(ch) || ch == '_')) s += ch; // letters and digits are fine cin.unget(); if (s == declkey) return Token(let); if (s == quitkey) return Token(quit); if (s == "sqrt") return Token(squareroot); if (s == "pow") return Token(power); if (s == constkey) return Token(con); return Token(name, s); } error("Bad token"); } } void Token_stream::ignore(char c) { if (full && c == buffer.kind) { full = false; return; } full = false; char ch; // searches input while (cin >> ch) if (ch == c) return; } class Variable { public: string name; double value; bool var; Variable(string n, double v, bool va) :name(n), value(v), var(va) { } }; class Symbol_table { public: static double get(string s); static void set(string s, double d); static bool is_declared(string s); static void predefine_name(string n, double val, bool var); static vector<Variable> names; }; double Symbol_table::get(string s) // returns the value of the Variable named s { for (unsigned i = 0; i < names.size(); ++i) if (names[i].name == s) return names[i].value; error("get: undefined name ", s); } void Symbol_table::set(string s, double d) // sets the value of the Variable named s { for (unsigned i = 0; i <= names.size(); ++i) if (names[i].name == s) { names[i].value = d; return; } error("set: undefined name ", s); } bool Symbol_table::is_declared(string s) // checks if there's already a Variable declared with name s { for (unsigned i = 0; i < names.size(); ++i) if (names[i].name == s) return true; return false; } Token_stream ts; double expression(); // analyzes expressions double primary() // analyzes primaries { Token t = ts.get(); // it gets a token from the token stream switch (t.kind) { case '(': { double d = expression(); t = ts.get(); if (t.kind != ')') error("')' expected"); break; } case squareroot: // layout: 's' + '(' + expression + ')' { t = ts.get(); if (t.kind != '(') error("'(' expected"); double d = expression(); if (d < 0) error("sqrt: the number must be positive"); t = ts.get(); if (t.kind != ')') error("')' expected"); return sqrt(d); } case power: // layout: 'p' + '(' + base + ',' + exponent + ')' { t = ts.get(); if (t.kind != '(') error("'(' expected"); double base = expression(); t = ts.get(); if (t.kind != ',') error("',' expected"); int exponent = narrow_cast<int>(expression()); t = ts.get(); if (t.kind != ')') error("')' expected"); return pow(base, exponent); } case '-': return -primary(); case number: return t.value; case name: { Token t_next = ts.get(); if (t_next.kind == '=') // handles name = expression { for (Variable& x : Symbol_table::names) if (x.name == t.name) if (x.var) { double new_value = expression(); Symbol_table::set(t.name, new_value); return new_value; } else error("can't change the value of a const"); } ts.unget(t_next); return Symbol_table::get(t.name); // it gets the value of the Variable } default: error("primary expected"); } } double term() // analyzes terms { double left = primary(); while (true) { Token t = ts.get(); switch (t.kind) { case '*': left *= primary(); break; case '/': { double d = primary(); if (d == 0) error("divide by zero"); // it's not possible to divide by zero, so it throws an error left /= d; break; } case '%': { int i1 = narrow_cast<int>(left); int i2 = narrow_cast<int>(primary()); if (i2 == 0) error("%: divide by zero"); // it's not possible to divide by zero, so it throws an error left = i1 % i2; break; } default: ts.unget(t); // puts the token back to the stream return left; } } } double expression() { double left = term(); while (true) { Token t = ts.get(); switch (t.kind) { case '+': left += term(); break; case '-': left -= term(); break; default: ts.unget(t); // puts the token back to the stream return left; } } } double declaration() // the function that works with the declaration of a new Variable { Token t = ts.get(); if (t.kind != name) error("name expected in declaration"); // if the kind of token isn't a name string new_name = t.name; if (Symbol_table::is_declared(new_name)) error(new_name, " declared twice"); // if the name was already declared before Token t2 = ts.get(); if (t2.kind != '=') error("= missing in declaration of ", new_name); // if "=" is missing in declaration, right after the name double d = expression(); // calls expression() for parsing the value of the new variable Symbol_table::names.push_back(Variable(new_name, d, true)); // adds the new Variable to the vector which holds all Variables return d; } double const_declaration() // the function that works with the declaration of a new const { Token t = ts.get(); if (t.kind != name) error("name expected in declaration"); // if the kind of token isn't a name string new_name = t.name; if (Symbol_table::is_declared(new_name)) error(new_name, " declared twice"); // if the name was already declared before Token t2 = ts.get(); if (t2.kind != '=') error("= missing in declaration of ", new_name); // if "=" is missing in declaration, right after the name double d = expression(); // calls expression() for parsing the value of the new variable Symbol_table::names.push_back(Variable(new_name, d, false)); // adds the new const to the vector which holds all Variables return d; } void Symbol_table::predefine_name(string name, double value, bool var) { if (is_declared(name)) error(name, " declared twice"); names.push_back(Variable(name, value, var)); } double statement() // analyzes statements { Token t = ts.get(); switch (t.kind) { case let: // if "let" was entered, starts the "process" of declaring a new Variable return declaration(); case con: return const_declaration(); default: ts.unget(t); // puts the token back and calls expression() for analyzing the input return expression(); } } void clean_up_mess() { ts.ignore(print); // discards Tokens up to and including the print character } const string prompt = "> "; const string result = "= "; void calculate() // it actually creates the loop for calculating multiple expressions { while (true) try { cout << prompt; Token t = ts.get(); while (t.kind == print) t = ts.get(); if (t.kind == quit) return; ts.unget(t); cout << result << statement() << endl; // calls statement() for evaluating the input further } catch (runtime_error& e) { cerr << e.what() << endl; clean_up_mess(); } } int main() try { Symbol_table::predefine_name("k", 1000, true); calculate(); return 0; } catch (exception& e) { cerr << "exception: " << e.what() << endl; char c; while (cin >> c && c != ';'); return 1; } catch (...) { cerr << "exception\n"; char c; while (cin >> c && c != ';'); return 2; } |
#4
Posted 15 September 2018 - 11:21
Campurile statice din clase/structuri trebuie "declarate" din nou intr-un cpp.
static vector<Variable> Symbol_table::name; |
#5
Posted 15 September 2018 - 11:45
Am inteles. Trebuia ca acea "declaratie" sa fie plasata dupa declararea si "corpul" clasei Symbol_table, nu?
Din cate am inteles, acel static reprezinta faptul ca o functie, spre exemplu, ce este membru al unei clase oarecare, precedata de acest static, poate fi invocata in mod independent, fara a fi nevoie de vreun obiect (adica obiect.functie()), nu? Edited by AnduIX, 15 September 2018 - 11:45. |
#6
Posted 15 September 2018 - 13:14
AnduIX, on 15 septembrie 2018 - 11:45, said:
Am inteles. Trebuia ca acea "declaratie" sa fie plasata dupa declararea si "corpul" clasei Symbol_table, nu? Din cate am inteles, acel static reprezinta faptul ca o functie, spre exemplu, ce este membru al unei clase oarecare, precedata de acest static, poate fi invocata in mod independent, fara a fi nevoie de vreun obiect (adica obiect.functie()), nu? static inseamna ca nu programezi OOP. |
#7
Posted 15 September 2018 - 13:56
Am inteles. Faptul ca nu fac POO nu este un lucru bun, cel putin in cazul folosirii limbajului C++, nu?
Problema a fost rezolvata datorita voua. Multumesc mult, baieti! Apropo, in declaratia ulterioara, cea de dupa corpul clasei Symbol_table, nu a trebuit sa mai adaug "static". Metoda prin care as putea evita folosirea "static" ar fi sa nu declar acele functii si acel vector in interiorul clasei, nu? Cred ca asa ar fi cel mai simplu. Pana acum asa am abordat scrierea codului, insa daca exercitiul mi-a cerut sa fac o noua clasa, am facut-o. |
#8
Posted 15 September 2018 - 19:14
#9
Posted 15 September 2018 - 19:37
#10
Posted 15 September 2018 - 22:23
- Comentariile nu au sens atunci cind numele variabilei/functiei/etc este cit se poate de clar
const char name = 'a'; // name Token kind Daca ai proasta idee sa numesti variabilele de genul "xjgb" atunci probabil ca ar fi o idee sa comentezi - Incearca sa gindesti numele de functii ca actiuni, adica sa contina un verb cit mai descriptiv. De exemplu pentru mine functia "expression()" sau functia "primary()" nu-mi spune nimic. Degeaba pui comentariu acolo unde o definesti, codul trebuie sa fie cit mai usor si rapid de inteles acolo unde functia este folosita. Practic comentariile nici nu trebuie sa existe decit acolo unde treburile sint cu adevarat imputite, codul trebuie sa se autodescrie. Pe vremuri, cind codul se scria manual, exista un motiv plauzibil pentru tot felul de prescurtari, acum cind exista autocomplete si scrii doar 2-3 litere, nu mai exista nici o scuza pentru a-l supune la chinuri pe fraieru care vine peste enspe ani sa faca un bug - POO nu trebuie sa fie o religie. Functiile statice au si ele rolul lor |
|
#11
Posted 16 September 2018 - 15:18
Iti multumesc mult pentru sfaturi! Voi tine cont de ele!
|
#12
Posted 17 September 2018 - 09:39
AnduIX, on 16 septembrie 2018 - 15:18, said:
Iti multumesc mult pentru sfaturi! Voi tine cont de ele! Proprietatile statice sunt mereu nasoale, evita-le; ele sunt variabile globale. |
#13
Posted 17 September 2018 - 15:20
Inteleg. Multumesc!
Doresc sa mai spun ceva, numai ca este cam off-topic. Dupa cum am precizat in urma cu cateva zile, eu invat programare folosind cartea "Programming: Principles and Practice using C++", scrisa de Bjarne Stroustrup. Cartea este orientata catre incepatori si asa si pare. Conceptele si modul de a scrie cod din carte sunt orientate catre realitate, te invata cum sa scrii cod organizat si cat mai bine, astfel incat sa poti face atat tu debugging mai usor (avand cod bine structurat), cat si celelalte persoane care vor vedea codul. Pare a fi o carte paralela cu ceea ce se face in liceu / facultate. In a XI-a n-am vazut si nici nu cred ca vom invata sa folosim clase. In carte se foloseste std::vector, ce se poate redimensiona foarte usor, la liceu folosim tablouri (arrays). In carte nu se vorbeste despre niciun algoritm de sortare, ci se foloseste sort(). Ce-i drept, nu este o carte de algoritmica, dar ca idee. Probabil ca trebuie sa combin mai multe carti, mai multa documentatie, pentru a putea dobandi cunostinte din mai multe surse si pentru a-mi mari orizontul. Cu toate acestea, eu unul cred ca "Programming: Principles and Practice using C++" este o carte buna, insa voi stiti mult mai bine decat mine. Am auzit ca este o carte buna, importanta, insa as dori si parerile voastre. Multumesc! |
#14
Posted 17 September 2018 - 17:02
Programarea se bazeaza pe abstractizari.
Cand inveti ce-i aia o sortare, scrii tu diversi algoritmi. Cand ai doar nevoie, folosesti ce exista deja. |
#16
Posted 18 September 2018 - 00:38
AnduIX, on 17 septembrie 2018 - 15:20, said: Cu toate acestea, eu unul cred ca "Programming: Principles and Practice using C++" este o carte buna, insa voi stiti mult mai bine decat mine. Am auzit ca este o carte buna, importanta, insa as dori si parerile voastre. Multumesc! Ai atitudinea potrivita; persevereaza. Pentru algoritmi, hmm... poate Sedgewick? Edited by TS030, 18 September 2018 - 00:40. |
#17
Posted 18 September 2018 - 15:19
TS030, on 18 septembrie 2018 - 00:38, said:
Spre deosebire de programa scolara, cartea respectiva isi propune sa faca un lucru dar sa-l faca bine. Continua, apoi treci la urmatoarea carte buna, apoi la urmatoarea (cu practica de rigoare, constanta - cum de altfel te si indeamna Stroustrup) si tot asa. Ai atitudinea potrivita; persevereaza. Pentru algoritmi, hmm... poate Sedgewick? Inteleg. Multumesc mult! Voi incerca sa fiu constant si sa mentin un echilibru intre munca si relaxare. Cartea de algoritmica recomandata de tine, cea scrisa de Robert Sedgewick, pare interesanta. Am auzit si de "Introduction to algorithms", de Cormen. Am tot vazut ca este recomandata. Ce parere aveti? Edited by AnduIX, 18 September 2018 - 15:39. |
#18
Posted 18 September 2018 - 15:29
Anunturi
▶ 0 user(s) are reading this topic
0 members, 0 guests, 0 anonymous users