C++ conditional include file runtime

2019-01-19 06:14发布

I am working on a game that is coded in C++ and I would like to make it possible to change language at runtime. Currently, the language is chosen at compile time by including a header file (which has language definitions), like so:

#include "lan_eng.h"

Therefore, the game does not allow the language to be changed once the client has been compiled. My question is if there is a way in which I can include files conditionally at runtime? I am new to C++, so at first I was thinking that I could do something like this:

#define DEF_LANGUAGE_ENG
//#define DEF_LANGUAGE_DEN

#ifdef DEF_LANGUAGE_ENG

    #include "lan_eng.h"

#endif

#ifdef DEF_LANGUAGE_DEN

    #include "lan_den.h"

#endif

Sure that makes it easier to maintain, but the problem is that I believe it only works at compile time. I would like to be able to store the chosen language in a variable (which is changed at runtime) and then use that variable to choose which header file to include. Is there a way to do this with header files, or would I be forced to make a class?

I hope it is not a stupid question; my searches did not give me the results I was hoping for.

Thanks in advance!

标签: c++ include
4条回答
放荡不羁爱自由
2楼-- · 2019-01-19 06:49

Pre-processing (#include, #ifdef, #define, etc) actually happens BEFORE compilation. You can think of pre-processing as text replacement, the output of which is the source code fed to the compiler. #defines and such occupy a separate namespace from variables in your program, and by the time your program is compiled, all of that is set in stone. In other words, what you are asking for is NOT possible.

To better understand this, look at your compiler options and look for an option that lets you keep the pre-processed output.

What you need to do instead is change how your string handling works. Instead of changing out the strings at compile time, you need to do something at runtime.

Check your platform - on most platforms there are APIs for doing localization. They vary by platform, though, so if you are doing a cross platform app, then you might have to roll your own.

查看更多
啃猪蹄的小仙女
3楼-- · 2019-01-19 06:51

You cannot do it with #include, that's compile time only. More specifically, that's pre-processor only, which happens before compilation.

To get run-time variation, you'll have to move your translations to a text file (something like xml perhaps, but plain text works too) and set up a system that loads the file at startup to populate the strings in the code that need translation.

This also means all your strings will be dynamically sized at start-up, so the initialization period for the code will increase. But that's the cost of flexibility sometimes.

查看更多
戒情不戒烟
4楼-- · 2019-01-19 06:59

You can not change #include's at runtime due to them being evaluated during compile time only.

What you can do instead, is have "language sheets". You can build a system that you reference during runtime, or you can have several text documents (such as .xml files) that you read and store when you want to change languages. Doing it this way also allows your application to be extended upon by users of the software in the future, as it will not be hardcoded.

If you design it in such a way, you could keep all your "language sheets" in one folder, then have your program check that folder for all available language sheets. This will allow users to also add languages to your program.

What you will basically need to do is create a string table, which can be done as part of a hardcoded method, or as part of a more dynamic method (mentioned as the language sheets).

查看更多
5楼-- · 2019-01-19 07:06

Perhaps the easiest way I've thought of is:

struct language {
    virtual str::string greeting() =0;
    virtual str::string greeting(const std::string& name) =0;
    virtual str::string goodbye() =0;
    virtual ~language() {}
};
struct English_language {
    virtual str::string greeting() {return "Hello";}
    virtual str::string greeting(const std::string& name) {return "Hello "+name;}
    virtual str::string goodbye() {return "Goodbye";}
} English;
struct German_language {
    virtual str::string greeting() {return "Hallo";}
    virtual str::string greeting(const std::string& name) {return name+" Hallo";}
    virtual str::string goodbye() {return "Auf Wiedersehen";}
} German;
language* CurLanguage = &English;

int main() {
   std::cout << CurLanguage->greeting("Steve") << '\n';
   CurLanguage = &German;
   std::cout << CurLanguage->goodbye() << '\n';
}

[EDIT] I rewrote it from scratch, since I realized pure virtual functions are a way to error at compile time if you miss a sentence, making maintenance much simpler. This version also has the ability to handle variables (dates, names, times, numbers, etc) neatly. This concept is based off what we use at my job, for over 2900 phrases/sentences in ~20 languages.

查看更多
登录 后发表回答