问题
As an example lets say I have a class called File
. Now file can be opened as binary or text. My constructor is currently File(const char*filename)
. Let's suppose the implementation of open is completely different binary and text. How the heck do I construct this?
I thought about using a static function but I don't want to return a pointer. I could pass in a pointer but I rather not allow a class be constructed without actually initializing it.
I was thinking about having an enum or bool in the constructor but it feels 'wrong' to me (and the way I may do this). I could have a different class name for binary and text and have both inherit a base implementation (or the other implementation) even though the only difference is the constuctor.
What's the most idiomatic way of doing this in C++?
回答1:
Two idiomatic ways are a factory function (nothing forces you to return a pointer), or tag dispatching (which is used in the standard library, for example in std::variant).
// Factory functions
struct File {
static File openText(char const *filename);
static File openBinary(char const *filename);
};
// Tag dispatching
struct open_as_binary_t {} constexpr open_as_binary;
struct open_as_text_t {} constexpr open_as_text;
struct File {
File(char const *filename, open_as_binary_t);
File(char const *filename, open_as_text_t);
};
回答2:
Add a flag
enum class open_mode
{
binary,
text
};
File(const char* filename, open_mode mode);
or use a tag
struct binary_tag { };
struct text_tag { };
File(const char* filename, binary_tag);
File(const char* filename, text_tag);
回答3:
I could have a different class name for binary and text and have both inherit a base implementation (or the other implementation) even though the only difference is the constuctor.
Yes, in general, I can propose to use the polymorphism. It is always clean, easy maintainable, extensible and understandable. Very flexible. The best for creating something could be the factory design pattern.
Example:
class File{ protected: File(); ... }; // make constructor protected!
class BinFile : public File;
class TextFile : public File;
Then you could use it in the ordinary way:
File *f = new BinFile;
File *f = new TextFile;
Place all common stuff in class File Implement any specific functionality per child class.
Then you could engage some factory method like:
File * OpenFile( String pathToFile, "TextFile" );
File * OpenFile( String pathToFile, "BinFile" );
In general, in this way, the code is very flexible.
回答4:
Why not even simpler:
File(const char *filename,const char *mode)
{
fl=fopen(filename,mode);
//
}
And simply call with myFile = File("log.txt","rt");
来源:https://stackoverflow.com/questions/61887903/whats-the-most-idotomatic-way-of-declaring-two-constructors-with-the-same-args