Let say I am designing an interface, to return the name of the child class. Note that, for different instance of a child class, their name shall remain the same.
For speed and memory efficient, I would say 3rd method signature is probably the best (based on some comment from char* vs std::string in c++)
virtual const std::string& name2() const = 0;
I was wo开发者_JAVA百科ndering is there any better alternative?
#include <cstdio>
#include <string>
class baby_interface {
public:
virtual const char* name0() const = 0;
virtual std::string name1() const = 0;
virtual const std::string& name2() const = 0;
};
class baby : public baby_interface {
public:
virtual const char* name0() const
{
return "My Baby";
}
virtual std::string name1() const
{
return "My Baby";
}
virtual const std::string& name2() const
{
return std::string("My Baby");
}
};
int main()
{
baby b;
// Refer to same char array address.
printf("%x\n", b.name0());
printf("%x\n\n", b.name0());
// Refer to different char array address.
printf("%x\n", b.name1().c_str());
printf("%x\n\n", b.name1().c_str());
// Refer to same char array address.
printf("%x\n", b.name2().c_str());
printf("%x\n\n", b.name2().c_str());
getchar();
}
It can be if you do it correctly. What you have now is undefined:
virtual const std::string& name2() const
{
return std::string("My Baby"); // constructs temporary string!
}
You're returning a reference to a temporary. For this to work, it must be an l-value. You could make it static:
virtual const std::string& name2() const
{
static const std::string result = "My Baby";
return result;
}
Or a member of the class, etc. Now it returns a usable variable.
I don't have much experience in what's common, but I'd guess number one is common if these interfaces are being used between modules. (i.e., the interface as allocated from a shared library/dll). This is because the implementation of strings is likely differ between compilers, and sometimes even different versions of the same compiler. If the program was made with one implementation, while the derived's was made in another, transferring between the two could fail.
By using a const char *
(which is the same in all compilers), you avoid that. However, const char *
can look unsightly to some.
The second options seems to be what I would use, because forcing derived classes to make a static/l-value variable might not be what you should do. The copy is likely to be very quick anyway.
Returning by value (your name1) is actually the most flexible, as it poses the least restrictions on any subclasses.
Returning a const reference (your name2) requires the subclass to store the data, as your code above shows, since you have Undefined Behavior returning a reference to a local (temporary) object.
Returning a pointer (your name0) is common when the strings are known at compile-time, as regular string literals can be used easily and with no overhead.
The third message signature doesn't work: You are returning a reference to an object that is destroyed when the method exits. Returning a reference makes sense when the object has a lifetime longer than the method call (eg. it is a member variable, a static, etc.).
The first two are OK; an third alternative is:
void name3(std::string* target) const
{
*target = whatever;
}
Basic tradeoffs:
const char* is good for communicating with C code, and when the strings are real constants with a long lifetime, also when crossing module boundaries where the runtime environment might not be consistent.
std::string is good when the contents of the string are generated in the method and the caller needs to take responsibility for the lifetime of the object. Whether you return a value or pass a pointer/reference for the method to modify is a detail.
const std::string& is good when there is a well-defined lifetime for the reference and it makes sense in the context of the actual method. This is good when strings are generated in a class and repeatedly used.
The return type depends on your usage. If you are returning a constant you should use either option 0 or 1 (const char* or std::string) with const char*
being a little more flexible (the user can capture it as a C-string or else as a c++ string), and std::string
being more c++-like. I would rather go for the second.
On the other hand, if you are returning a value that you already have stored (a member attribute) then I would go for 2. There is no need to create a copy, and a C-style string would require managing memory ownership and documenting (is the caller responsible for deletion, or is the memory managed elsewhere? how long is the pointed value valid (.c_str()
will become invalid after some mutating operations on the string).
So to sum up:
class X {
std::string name_;
public:
const char* constant1() const { return "constant"; }
std::string constant2() const { return "constant"; } // preferred over constant1
std::string const & name() const { return name_; } // internal data
std::string const & constant3() const {
// valid, more complex than needed, requires creating static data
static std::string the_constant = "constant";
return the_constant;
}
};
精彩评论