Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
429 views
in Technique[技术] by (71.8m points)

singleton - How to simulate 'friend' in C++ with int main()

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
Waitting for answers

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...