Obiekt uniemożliwia wykonanie main()

0

Witam. Mam problem - kiedy tworzę obiekt klasy Files, main() się nie wykonuje (żadna funkcja nie jest wywołana), a plik .exe zamyka się się po chwili. Próbowałem przepisywać definicję klasy i kompilować tylko ją (.h, bez pliku .cpp), ale to nie pomogło. Wszystkie klasy wyglądają podobnie - każda dziedziczy tylko z klasy Client. Problem jest tylko z tą. Nie ma też żadnych ostrzeżeń podczas kompilacji.

Plik Files.h: https://pastebin.com/E3WarUVq
Plik Files.cpp (bez niego problem nie znika): https://pastebin.com/cGKATu7h

Mogę zamieścić cały kod, jeżeli będzie potrzebny.

0

A cóż to są za bloki:

if (ConfigFile << "#Use ';' at the end of each line, except comments\n\n") {}
            else std::cerr << ERROR_CONFIG;

...i wiele temu podobnych?

0

Dodawanie linii do pliku ConfigFile

A czemu stosujesz tak dziwaczne konstrukcje?

PS: Nie odpowiadaj w komentarzach tylko w postach pod pytaniem.

0

@grzesiek51114: Czemu dziwaczne? Jeżeli wstawienie linii do pliku się nie powiedzie to wyświetlam "swoje" ostrzeżenie.

0

Dawno już nie robiłem w C++ ale na pewno te dziwne ify da się zastąpić czymś lepszym, bo to aż wypala oczy. :-)

1

Przede wszystkim wstaw maina bo co może powiedzieć o wykonaniu programu sama klasa?

0

@grzesiek51114: Mógłbym to zastąpić obsługą wyjątków, ale w tym przypadku rodzaj wyjątku nie ma znaczenia, chodzi tylko o to, czy wstawienie do pliku się powiodło.

2

Każda funkcja, która ma więcej niż 2 - 3 instrukcję sterujące (if for while switch) przyprawia mnie o ból głowy (i zapewne wszystkich innych, ale się boją przyznać).
Im mniejszymi funkcjami piszę się kod, tym bardziej jest czytelny i tym bardziej jest "samo dokumentujący" się (zamiast komentarzy są nazwy funkcji).

Gdzie jest mian?
Pewnie masz zmienne globalne, których inicjalizacja kończy się błędem i dlatego main nie startuje.

0

Main: https://pastebin.com/7hAdAivB

@MarekR22 Nie mam żadnych zmiennych globalnych.

0

current_path
Co to jest i jak jest inicjowane.

0

Wstawiam Client.h: https://pastebin.com/jLd1pdqD
@Mistrzowski Ogórek Jedna (std::string) w main, druga (std::string&) w klasie Client.

1

Czyli przekazujesz do inicjalizacji "var" zmienną "var" o tym samym adresie? Jaki to ma sens? Podejrzewam że tu jest błąd. Każesz przypisać się zmiennej samej do siebie PRZED jej pierwszą inicjalizacją (ma nieokreślony stan). To nie może się skończyć dobrze.

#include <iostream>
#include <string>

class Base {
public:
	Base(std::string &str)
		: str(str) {}
	std::string &str;
};

class Derived : public Base {
public:
	Derived() : Base(str) {}
};

int main() {
	Derived d;
	std::cout << d.str;
}

Takie coś się wysypuje od razu

0

Dlaczego ten błąd występuje tylko dla Files? I jak mogę tego używać, żebym nie musiał stosować konstruktora z referencjami w każdej klasie?

1

Inny powód wykrzaczenia się, to linkowanie się statyczne do dll-ki, której program nie może zlokalizować.

Radzę ustalić jakie jest źródło błędu (komunikat o błędzie), bo wróżymy z fusów.

0

Pewnie w innych sytuacjach nie używasz tych zmiennych, albo inicjujesz je dobrze. To co robisz ogólnie nie ma sensu, masz złe podejście, robisz niektóre rzeczy źle i o tym nie wiesz. Zapoznaj się z referencją w C++, czym jest, kolejność inicjalizacji w konstruktorach, referencja na pointer i inne takie sprawy, a następnie wróć do tego i popraw te fragmenty.

Poprawka na szybko:

  1. usuń & (ze zmiennych Client)
  2. wywołuj domyślne konstruktory - zmienna() na liście inicjalizacyjnej konstruktora
0
  1. Po usunięciu & występują błędy podczas kompilacji:
attempting to reference a deleted function 
  1. To nie jest domyślny konstruktor?.
Files() : Client(MySQL, SaveFile, Log_save, people, current, current_path,
			logstream, valuesList, databaseList, memberList) {}
0

Jeżeli chcesz żeby zmienne które masz w klasie Client należały tylko i wyłącznie do niej to usuń referencje z ich deklaracji. Jeżeli chcesz żeby wskazywały na jakieś zewnętrzne źródło zamień je na pointery, gdyż pointer może być pusty (nullptr), a referencja w normalnych warunkach nie. Stwórz konstruktor domyślny klasy Client, który nie robi nic (lub zeruje ewentualne zmienne) i wywołuj go dalej w klasach dziedziczących.

Podrzucam pierwszy lepszy
https://www.tutorialspoint.com/cplusplus/cpp_references.htm

0

Chodzi o to, żeby zmienne z & w klasie Client były inicjowane za pomocą ClientInstance() z main(), a następnie dziedziczone do innych klas (jako referencje do main) - tak jak w przykładzie @Mistrzowski Ogórek. Nie wiem, czy coś to zmieni, jeżeli zamienię referencje na wskaźniki (nie potrzebuję nullptr, bo zmienne w main() są inicjowane przed stworzeniem obiektu Client).

0

Nie przekazujesz ich i w tym problem.
Polecam inne podejście.
Tworzysz sobie taki pojemnik na różne rzeczy i przekazujesz go dalej i zapisujesz w klasach jako pointer/referencję. Wygodniejsze niż dziedziczenie.

0
struct Variables {
	bool current_;
};
class Client
{
	protected:
		Variables *var;
		void x() {
			var->current_ = true;
			std::cout << var->current_;
		}
}

Czy to może działać? Gdybym zadeklarował wskaźnik var w Client, mógłbym go używać w pochodnej klasie Files?

0

Niech Client będzie tym wskaźnikiem. Nie ma sensu tworzyć zmiennych w mainie i zapisywać ich adresów do obiektu który przekażesz dalej. Tworzysz jeden obiekt i go przekazujesz i zapisujesz w klasach jako referencję/pointer, zależnie od tego czy jest zawsze obecny czy nie. Z dziedziczenie lepiej całkowicie zrezygnuj. To nie działa w ten sposób w jaki chciałeś.

0

Stworzyłem strukturę, do której przeniosłem wszystkie zmienne, które wcześniej inicjowałem w konstruktorze.

struct ClientVariables {
	bool MySQL;
	bool SaveFile;
	bool Log_save;
	unsigned people;
	std::string current;
	std::string current_path;
	std::stringstream logstream;
	std::vector<std::string> valuesList;
	std::vector<std::string> databaseList;
	std::vector<std::vector <std::string> > memberList;
};

Następnie utworzyłem wskaźnik *var w klasie Client, usunąłem wszystkie konstruktory (które nie były już potrzebne) i dodałem "var->" do nazw zmiennych we wszystkich klasach. Niestety, problem nie zniknął i dalej nie mogę utworzyć obiektu klasy Files.

Zaktualizowane pliki:
Client.h: https://pastebin.com/kUyMiGY1
Files.h: https://pastebin.com/D3UbJgvT
Files.cpp: https://pastebin.com/tR9gX4nF

1

Nie o to mi chodziło.
Niech Client będzie memberem tych wszystkich twoich klas które z niego dziedziczą (pointer albo referencja).
Wtedy ominiesz problem inicjalizacji i każda dziedzicząca wcześniej go klasa będzie go teraz współdzielić (w konstruktorze każdej takiej klasy będziesz przekazywał na niego pointer).

0

Mógłbyś podać jakiś przykład? Powinienem przekazywać wskaźnik do ClientVariables (struktura) za pomocą konstruktora do klas pochodnych?

1

Pole var nigdy nie jest zainicjowane, to wszystkie skutki Undefined Begaviouru są możliwe. Zrób konstruktory i porządnie inicjuj pola.

W/w jest szybką intuicją z tego kodu, bo jest straszny i wg rach prawdopodobieństwa niejedna mina w nim jest.

0

Do klasy Client dodałem

ClientVariables variable;
ClientVariables * var = &variable;

i program zdaje się działać, mam tylko problem ze zmiennymi - kiedy w jednej klasie zmieniam wartość zmiennej x, w innej pozostaje taka sama (w każdej klasie tworzę inny obiekt variable). Jak, za pomocą konstruktora, mogę przekazać wskaźnik *var z klasy Client do klasy pochodnej?

1

Już po pracy to nie z anonima

#include <iostream>
#include <string>
using namespace std;

struct ProgramOptions {
	std::string configName;
	std::string filePath;
	bool fileUsed;
};

class FirstUser {
public:
	FirstUser(ProgramOptions *options)
		:options(options) {}
	void whatsMyFile() const {
		std::cout << options->fileUsed << ' ' << options->configName << '\n';
	}
private:
	ProgramOptions *options;
};

class SecondUser {
public:
	SecondUser(ProgramOptions *options)
		:options(options) {}
	void whatsMyPath() const {
		std::cout << options->fileUsed << ' ' << options->filePath << '\n';
	}
private:
	ProgramOptions *options;
};


int main() {
	ProgramOptions options;
	options.configName = "nice-config";
	options.filePath = "/usr/nice/file";
	options.fileUsed = false;
	
	FirstUser user1(&options);
	SecondUser user2(&options);
	
	user1.whatsMyFile();
	options.fileUsed = true;
	user2.whatsMyPath();
}

Chodzi mi o coś takiego. Z dziedziczenia po prostu zrezygnuj. Nie używaj go. przekazuj swój "Client", przez chociażby pointer, dalej i zapisuj w obiektach. Nie dziedzicz z niego, bo przez dziedziczenie nie będzie współdzielenia

0

Nie można tego zrobić w podobny sposób (ten kod nie działa)?
Files.h

ClientVariables * var;
Files() : Client(), var(Client::var) {}

Wolałbym użyć domyślnego konstruktora i nie używać ClientVariables w main().

1

Jeżeli z jakiegoś powodu dependecy injection przez konstruktor ci nie pasuje, zostaje ci injection przez setter albo użycie singletona.

W twoim rozwiązaniu dalej jest błędne przekonanie że twój client się będzie jakoś współdzielił. Nie będzie. Ta sama nazwa nie oznacza tej samej zmiennej.

0

Dodałem przekazywanie przez konstruktor, jak radził @arciobus, i program działa. Jeden argument w postaci struktury wygląda lepiej niż kilkanaście osobnych.

Dziękuję wszystkim za pomoc.

1 użytkowników online, w tym zalogowanych: 0, gości: 1