Jak utworzyć i przekazać obiekt do innego obiektu?

0

Witam

Tworzę aplikację i mam pewien problem. Zacznijmy od tego, że są klasy np.:

class Text
class Przycisk
{
   Text txt; 
};

Pytanie mam jak po utworzeniu obiektu klasy Przycisk przekazać go do do innego obiektu np. Menu? W tej chwili, przekazując Przycisk do Menu, tracę gdzieś po drodze Text. Czego objawem jest zgłoszenie przez aplikację komunikatu "Access violation reading location " w momencie gdy ma wyświetlić tekst na ekranie.

0

To masz na myśli? Czy o coś związanego z dziedziczeniem pytasz?

class Text
{
public:
    Text() {}
    string zmienna;
};

class Przycisk
{
public:
    Przycisk() {}
    Text txt;
};

class Menu
{
public:
    Menu() {}
    Przycisk przycisk;

};

int main()
{
    Menu obiekt;
    obiekt.przycisk.txt.zmienna = "tekst";
    return 0;
}
0

Na myśli ma:

Class Text
{
public:
Text();
sf::Text;
}

Class Przycisk
{
Public
Przycisk();

Text txt;
}

Class Menu
public:
Menu();

void wstawPrzycisk(Przycisk &btn);
}

Int main
{
Przycisk przy;
Menu mnu;

przy.txt.funkcja();

mnu.wstawPrzycisk(przy);
}
0

Dokładnie to mam na myśli, co przedstawił Trzeźwy Szczur. Próbowałem z konstruktorem kopiującym, ale nie pomogło. Jeśli mam sam obiekt przycisk bez klasy Text, Wszystko działa prawidłowo w momencie dodania do przycisku klasy Text otrzymuje:

Exception thrown at 0x0F7CAB3F (sfml-graphics-d-2.dll) in #####: 0xC0000005: Access violation reading location 0xCCCCCD24

Dlatego myślę, że problem jest, że gdzieś "gubi" się obiekt Text. Czy konstruktor przeniesienia załatwił by sprawę?

0

wyczuwam problem wskaźników

0

Wszystko zależy od sposobu ich przechowywania i od tego, co chcesz robić z oryginalnym obiektem (na przykład z przyciskiem) gdy już go przekażesz. Możesz:
1. Trzymać i przekazywać obiekty poprzez std::move.
2. Trzymać obiekty jako wskaźniki - jeśli chcesz bezpiecznie je współdzielić.

Przez referencję Ci się nie uda - gdy obiekt umrze będziesz przechowywał referencję na nieistniejący obiekt.

edit: Polecam jednak opcję drugą - wskaźniki. Jeśli potem Twój program/system ma być bardziej rozbudowany to std::shared_ptr rozwiąże lub pomoże Ci uniknąć wielu problemów.

0

Chciałbym utworzyć obiekt Przycisk w funkcji innej klasy, a następnie przekazać go na "własność" klasie menu. Zrobiłem to tak:

class Button : public Object
{

private:
	MyText txt; //z tym jest problem
};



class Menu
{

public:
	void setButton(const Button &btn);

private:
	vector <unique_ptr<Button>> arrayButtons;
}

//realizacja
void Menu::setButton(const Button &btn)
{

	arrayButtons.push_back(std::make_unique<Button>(btn));
	numberButtons = numberButtons + 1;
}
0

Rozumiem, że to co wrzuciłeś to oryginalny Twój kod, nie przykład? Może wrzuć całość i pokaż sposób w jaki korzystasz w Menu z obiektu txt w klasie Button.

0

Tak, to jest fragment mojego kodu. Poniżej wklejam większą jego część:

////////////////////////
//klasa MyText
//////////////////////

class MyText
{
public:
	void initText(sf::RenderWindow *tm, std::string nameFont, sf::Vector2f tempPosition,  unsigned int size = 12);
	void setColorText(sf::Color color);
	void drawText();
	void setPositionText(sf::Vector2f tempPosition);
	void setSize(unsigned int size) noexcept;
	void setStyleText(sf::Text::Style style);
	void setText(sf::String);
	sf::String getText();
	unsigned int getSize();

	MyText();
	virtual ~MyText();


protected:
	sf::Font font;
	sf::Text text;
private:
	sf::RenderWindow *renderText;
	StringTransform trans;
	unsigned int sizeText;
};


////////////////////////
//klasa Button 
//////////////////////

class Button : public Object
{
	enum class enuAlignmentText
	enum class enuAlignmentPicture
public:
	enum class enuButtonStatus

	void initButton(std::string name, sf::RenderWindow *tempWindow, AppTexture *tempResurces, int startFrame);
	void setPicture(float tWidth, float tHight, int frame);
	void setButtonBox(Object::sCoordinate temp, ObjectBox::enuTypeBox tTypeBox, float radius = 0);
	void changePositionButton(Object::sCoordinate temp, float radius = 0);
	void setVisiblyButton(bool visibly) noexcept;
	void setActivedButton(bool activ) noexcept;
	void setText(sf::String tText, string tFont, int size, sf::Color color = sf::Color::Black);
	void isTextButton(bool textIs) noexcept;
	void isPictureButton(bool pictureIS) noexcept;
	Button::enuButtonStatus getButtonStatus() noexcept;
	void toBeNormal() noexcept;
	bool mouseOver(sf::Vector2f vec);
	bool mouseClick(sf::Vector2f vec);

	virtual void drawEx() override;
	virtual void update() override;


	Button();
	~Button();
protected:

private:
	int offset;
	bool isVisible;
	bool isText;
	bool isPicture;
	enuButtonStatus buttonStatus;
	enuButtonStatus oldButtonStatus;
	enuAlignmentText aligmText;
	enuAlignmentPicture aligmPicture;

	int numberFirstFrame; //przypisany pierwszej klatce dla satusu normal
	int actualFrames;
	sf::String buttoText;
	ObjectBox box;
	MyText txt;
	ObjectSimple Picture;

	sf::Vector2f calculatePositionText(sf::String tText, int size); //funkcja automatycznie przelicza pozycję w kontrolce button

};

//realizacja tylko funkcje gdzie jest tekst
void Button::drawEx()
{
	if (isVisible == true)
	{
		objectWindow->draw(arrayVortex, renderStates);

		if (isText == true)
		{
			txt.drawText();
		}

		if (isPicture == true)
		{
			Picture.drawEx();
		}
	}
}

void Button::setText(sf::String tText, string tFont, int size, sf::Color color)
{
	sf::Vector2f tempPosition;

	tempPosition = calculatePositionText(tText, size);

	txt.initText(objectWindow, tFont, tempPosition, size);
	txt.setPositionText(tempPosition);
	txt.setText(tText);
	txt.setColorText(color);
}


////////////////////////
//klasa Menu
//////////////////////

class GameMenu
{
	enum class enOrientationMenu

public:
	void setButton(const Button &btns);
	void setOffset(int offX = 0, int offY = 0) noexcept;
	void setIsBackgraound(bool is);
	void setBackgraound(std::string name, sf::RenderWindow *tempWindow, AppTexture *tempResurces, Object::sCoordinate temp, int frame);
	void changeOrientation(GameMenu::enOrientationMenu orientation) noexcept;
	void setPositonMenu(sf::Vector2f pos) noexcept;
	int whitchButtonPress();

	bool mouseOver(sf::Vector2f vec);
	bool mouseClick(sf::Vector2f vec);

	void drawMenu();
	void updateMenu();
	
	GameMenu();
	virtual ~GameMenu();

protected:

private:
	int offsetX;
	int offsetY;
	int numberButtons;
	int indexButtonPressed;
	sf::Vector2f positionMenu;
	bool isBackgraound;

	vector <unique_ptr<Button>> arrayButtons;
	ObjectSimple Backgraound;
	GameMenu::enOrientationMenu orientationMenu;
};

//realizacja tylko funkcje gdzie jest tekst
void GameMenu::setButton(const Button &btns)
{
	arrayButtons.push_back(std::make_unique<Button>(btns));
	numberButtons = numberButtons + 1;

}

void GameMenu::drawMenu()
{
	int i;


	if (numberButtons !=0)
	{
		if (isBackgraound == true)
		{
			Backgraound.drawEx();
		}

		i = 0;

		for (i; i < numberButtons; i++)
		{
			arrayButtons[i]->drawEx();
		}
	}
}


////////////////////////
//klasa AppMainWindow
//////////////////////

class AppMainWindow
{
public:
	void initAppMainWindow(sf::RenderWindow *tempWindow, AppTexture *tempMenu, AppTexture *tempResurces);

	void appDrawWindow();
	void update(float delta);
	void onEvent(sf::Event event);

	AppMainWindow();
	~AppMainWindow();
protected:

private:
	sf::RenderWindow *objectWindow;
	AppTexture *TexObject;
	AppTexture *TexMenu;
	vector <ObjectSimple> box;
	int numberBox;
	GameMenu mainMenu;
};

//realizacja tylko funkcje gdzie jest tekst

void AppMainWindow::initAppMainWindow(sf::RenderWindow *tempWindow, AppTexture *tempMenu, AppTexture *tempResurces)
{
	sf::Vector2f pos;
	Object::sCoordinate temp; //struktura przechowująca dane pozycji i wymiaru
	Button btn;

	objectWindow = tempWindow;
	TexObject = tempResurces;
	TexMenu = tempMenu;
	createBox();

	pos.x = 20;
	pos.y = 5;

	mainMenu.setPositonMenu(pos);

	temp.position.x = 396;
	temp.position.y = 5;
	temp.width = 96;
	temp.height = 24;

	btn.initButton("p", tempWindow, tempMenu, 8);
	btn.setButtonBox(temp, ObjectBox::enuTypeBox::enSquareBox);
	btn.isTextButton(true);
	btn.setText("Start", "dane/Tahoma.ttf", 14);
	mainMenu.setButton(btn);

}
0

Już lepiej tak będzie:

class GameMenu
{
	...

	void GameMenu::setButton(std::shared_ptr<Button> btn)
	{
		arrayButtons.push_back(btn);
	}	
	
private:
 	vector <std::shared_ptr<Button>> arrayButtons;
};




...


auto btn = std::make_shared<Button>();
btn->initButton("p", tempWindow, tempMenu, 8);
btn->setButtonBox(temp, ObjectBox::enuTypeBox::enSquareBox);
btn->isTextButton(true);
btn->setText("Start", "dane/Tahoma.ttf", 14);
mainMenu.setButton(btn);
0

Bardzo dziękuję to rozwiązanie pomogło. Jeśli dobrze zrozumiałem w sposób niewłaściwy przekazywałem obiekt innemu obiektowi. Powinienem najpierw stworzyć wskaźnik do obiektu, a potem przekazać go "w inne" miejsce.

0

Problemu szukałbym w kopiowaniu obiektu klasy Button, bo to, co zaproponowałem to pominięcie niepotrzebnego kopiowania.

0

Zrobiłem w każdej klasie Button i MyText konstruktory kopiujące. Niestety w nich też musiałem coś zrobić źle, ponieważ nie poprawiło to sytuacji.

Button::Button(const Button &button) {
	this->txt = button.txt; //klasa MyText
	this->isVisible = button.isVisible;
	//reszta danych kopiowania
}

MyText::MyText(const MyText &text) {
	this->renderText = text.renderText;
	this->font = text.font;
	//reszta danych kopiowania
}
0

Skoro zrobiłeś konstruktory kopiujące, to powinieneś też przeciążyć operatory przypisania. Choć z drugiej strony jeśli konstruktor kopiujący i operator przypisania będą robić dokładnie to samo co ich domyślne wersje, to nie ma sensu ich definiować.

Pokaż destruktory Object, MyText i Button.

Pokaż jeszcze MyText::initText, bo chyba tu jest błąd.

0

Destruktory tych klas są puste:

virtual ~MyText();

MyText::~MyText() //reszta destruktorów też tak wygląda
{

}


void  MyText::initText(sf::RenderWindow *tm, std::string nameFont, sf::Vector2f tempPosition,  unsigned int size)
{
	float x;
	float y;

	renderText = tm;
	sizeText = size;

	if (!font.loadFromFile(nameFont))
	{
		#if KOMPILACJA==1
			LogApp.writeLogEx("==================Nie udało się fontu wstawić  ==================");
		#endif
	}

	text.setFont(font);
	text.setCharacterSize(size);

	x = tempPosition.x ;
	y = tempPosition.y;
	text.setPosition(x,y);
}
0

Dobra, tu jest problem:

void  MyText::initText(...)
{
        ...
        text.setFont(font); // <---

        ...
}

Według dokumentacji sf::Text przechowuje wskaźnik na obiekt podany w parametrze metody setFont. Przy kopiowaniu ów wskaźnik jest kopiowany do kopii obiektu text (brak zdefiniowanego/zblokowanego operatora przypisania i ctora kop. - dziwne). Problem polega na tym, że obiekt font jest częścią klasy MyText, wystarczy, że obiekt źródłowy zostanie zniszczony, a wskaźnik będzie wskazywał na nieistniejący obiekt klasy sf::Font. Odwołanie się do niego, co oczywiste, musi wywołać błąd dostępu do pamięci.

Musisz zdefiniować konstruktor kopiujący i operator przypisania dla klasy MyText, gdzie this->text dostaje this->font.

0

Zrobię to, a dodatkowo zastanawiam się czy fontu nie potraktować jak każdy inny zasób (np. teksturę) i trzymać go w programie osobno.

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