I want to make a singleton class with no public methods. I have achieved this functionality with another class that is a friend
of my Main
(it has private methods access). But I want to make sure of the same functionality but in my main
function. For example, I want to be able to include my main.h
in many files, but deny them access to the Mainloop()
method, rather just allow it to only be called in my main.cpp
with the int main()
.
Here is my main.h
#pragma once
#ifndef MAIN_H
#define MAIN_H
#include <iostream>
#include <string>
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#include <SDL2/SDL_image.h>
#include "events.h"
class Main ///Singleton
{
public:
Main(const Main&) = delete;
Main(Main&&) = delete;
Main& operator=(const Main&) = delete;
Main& operator=(Main&&) = delete;
static void Mainloop(); ///THIS IS WHAT I WANT TO BE PRIVATE BUT STILL CALLABLE
private:
Main();
static Main& Get_Instance();
static void Init();
static void Free();
SDL_Window* window = nullptr;
SDL_Renderer* renderer = nullptr;
bool running = false;
char mainloopInstanceBlocker = 'I';
};
#endif // MAIN_H
and main.cpp
#include "main.h"
Main::Main()
{
std::cout << "Main constructor called
";
mainloopInstanceBlocker = 'C';
}
Main& Main::Get_Instance()
{
static Main instance;
return instance;
}
void Main::Init()
{
std::cout << "Main Init called
";
Get_Instance(); ///To initialize constructor in case it hasn't been
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
IMG_Init(IMG_INIT_PNG | IMG_INIT_JPG);
Get_Instance().window = SDL_CreateWindow("Program", 0, 30, 1280, 720, SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE );
Get_Instance().renderer = SDL_CreateRenderer(Get_Instance().window, -1, SDL_RENDERER_ACCELERATED );
Get_Instance().running = true;
SDL_StartTextInput();
}
void Main::Free()
{
SDL_StopTextInput();
SDL_DestroyRenderer(Get_Instance().renderer);
SDL_DestroyWindow(Get_Instance().window);
IMG_Quit();
TTF_Quit();
SDL_Quit();
std::cout << "Main Free called
";
}
void Main::Mainloop()
{
Get_Instance(); ///To initialize constructor
if (Get_Instance().mainloopInstanceBlocker == 'C')
{
Get_Instance().mainloopInstanceBlocker = 'B'; ///Begins at I (initialized), then C (constructed) then B (began)
///It works as it begins as constructed, then does the main loop, after set to B, won't enter again.
Get_Instance().Init();
Events::Get_Instance(); ///Initialize Events constructor
while (Get_Instance().running)
{
///Begin event handling
Events::Event_Loop();
if (Events::Quit_Application())
{
Get_Instance().running = false;
break;
}
///Clear display to color
SDL_SetRenderDrawColor(Get_Instance().renderer, 0,255,0,255);
SDL_RenderClear(Get_Instance().renderer);
///Non negotiable end loop functions
Events::Reset_Events();
SDL_RenderPresent(Get_Instance().renderer);
//SDL_Delay(1000/60);
}
Get_Instance().Free();
}
else
{
std::cout << "Called Main::Mainloop(); more than once
";
}
}
int main(int argc, char* argv[])
{
Main::Mainloop();
return 0;
}
events.h
#pragma once
#ifndef EVENTS_H
#define EVENTS_H
#include "main.h"
class Events ///Singleton
{
public:
Events(const Events&) = delete;
Events(Events&&) = delete;
Events& operator=(const Events&) = delete;
Events& operator=(Events&&) = delete;
///Mouse
static const SDL_Point& Mouse_Pos();
///Keyboard
static const std::string& User_Text_Input();
static const bool& User_Backspace();
private:
Events();
static Events& Get_Instance();
///Allow Main to access private members. Works well, one instance, only called once for those functions too. in Main
friend class Main;
///For event handling
static void Event_Loop();
///For event handling
static void Reset_Events();
///For quitting, used main only
static const bool& Quit_Application();
///For Event_Loop()
int eventLoopCounter = 0; ///To ensure Event_Loop() doesn't get used twice in the same loop
SDL_Event event;
bool m_quit = false;
///Mouse
SDL_Point m_Mouse_Pos = {0,0};
///Keyboard
std::string m_User_Text_Input = "";
bool m_User_Backspace = false;
};
#endif // EVENTS_H
and events.cpp
#include "events.h"
Events::Events()
{
std::cout << "Events constructor called
";
}
Events &Events::Get_Instance()
{
static Events instance;
return instance;
}
void Events::Event_Loop()
{
Get_Instance();
if (Get_Instance().eventLoopCounter == 0)
{
Get_Instance().eventLoopCounter += 1;
while (SDL_PollEvent(&Get_Instance().event) != 0)
{
if (Get_Instance().event.type == SDL_QUIT)
{
Get_Instance().m_quit = true;
break;
}
///Mouse
if (Get_Instance().event.type == SDL_MOUSEMOTION)
{
Get_Instance().m_Mouse_Pos = {Get_Instance().event.motion.x, Get_Instance().event.motion.y};
}
///Keyboard
if (Get_Instance().event.type == SDL_TEXTINPUT)
{
Get_Instance().m_User_Text_Input = Get_Instance().event.text.text;
//break; ///Break here for multiple key presses registered at once
}
///Keydown
if (Get_Instance().event.type == SDL_KEYDOWN)
{
if (Get_Instance().event.key.keysym.sym == SDLK_BACKSPACE)
{
Get_Instance().m_User_Backspace = true;
}
}
}
}
else
{
std::cout << "Called Events::Event_Loop(); more than once
";
}
}
void Events::Reset_Events()
{
Get_Instance().eventLoopCounter = 0;
Get_Instance().m_quit = false;
///Mouse
///Keyboard
Get_Instance().m_User_Text_Input = "";
Get_Instance().m_User_Backspace = false;
}
const bool& Events::Quit_Application()
{
return Get_Instance().m_quit;
}
///Mouse
const SDL_Point& Events::Mouse_Pos()
{
return Get_Instance().m_Mouse_Pos;
}
///Keyboard
const std::string& Events::User_Text_Input()
{
return Get_Instance().m_User_Text_Input;
}
const bool& Events::User_Backspace()
{
return Get_Instance().m_User_Backspace;
}
question from:
https://stackoverflow.com/questions/65854584/how-to-simulate-friend-in-c-with-int-main 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…