我有一个类需要在构造期间连接两个
const char*
字符串,甚至稍后在初始化列表中使用结果(连接的字符串)。
const char* SUFFIX = "suffix";
class widget {
public:
widget(const char* prefix) : key(???), cls(key) { };
private:
const char* key;
const important_class cls;
}
widget("prefix_"); // key should be prefix_suffix
有一个全局(在
widget
的cpp中)const char*
后缀,我想附加到用户提供的前缀。
怎么做?
顺便说一句。我听说过
string
。如果我可以使用string
我不会在这里问,关于const char*
使用
std::string
使您的问题成为一项微不足道的任务:
const std::string SUFFIX = "suffix";
class widget {
public:
widget(std::string const & prefix)
: key(prefix + SUFFIX), cls(key)
{ } // ^^^^^^^^^^^^^^concatenation!
private:
const std::string key;
const important_class cls;
}
widget("prefix_");
如果你需要
const char*
,你仍然可以通过调用 key.c_str()
得到它,它返回 const char*
。所以在你的情况下,它会给你 c-string "prefix_suffix"
.
另请注意,声明的顺序很重要,您已正确完成:
cls
必须在之后key
声明,因为其构造取决于key
.
用
std::string
作为中间值:
const char* SUFFIX = "suffix";
class widget {
public:
widget(const char* prefix) :
intermediate(string(prefix) + suffix),
key(intermediate.c_str()),
cls(key) {
}
private:
const std::string intermediate;
const char* key;
const important_class cls;
}
widget("prefix_"); // key should be prefix_suffix
此处与您的代码唯一不同的是私有成员变量,
intermediate
.
std::string
对象 intermediate
管理保持连接所需的动态内存。它会在异常、分配、复制等情况下很好地清理
只要
string
没有发生变化,const char*
返回的 c_str()
将保持有效。由于 intermediate
是 const
,不能对其调用任何变异函数,因此使用内部缓冲区的 cls
不应该有问题。
您应该使用 std::string (或您的项目使用的任何字符串类)。这将使这变得容易得多,并避免使这个异常安全的问题。
如果你坚持,
widget(const char* prefix) :
key(strcat(strcpy(new char[strlen(prefix)+strlen(SUFFIX)+1], prefix), SUFFIX)),
cls(key) { }
会用 C 的方式来做。
important_class
的构造函数不应该抛出异常。
如果您需要使用生成的
key
来初始化cls
,请注意保持声明的顺序。
最好使用
std::string
把你的弦放在一起。如果需要,您仍然可以致电 std::string::c_str()
获取 const char*
。 std::string::append
也以 const char*
作为参数。或者使用 +
-运算符。
见这里.
我不确定你能在初始化列表中做到这一点。当然,其他一些有更多经验的用户可以提供帮助......当然,这听起来很明显,但你可以使用 std::string 然后就可以了:
class widget
{
public:
widget(const char* prefix) : key(prefix)
{
string_key.append(suffix);
};
private:
const char* key;
std::string string_key;
};
当然,你可以这样做:
class widget
{
public:
widget(const char* prefix) : key(prefix)
{
key.append(suffix);
};
private:
std::string key;
};
我错过了整个“important_class”部分。它在这里代表什么?你想达到什么目的?.
希望有帮助。
我看到两个选项,具体取决于您对价值持久性等的需求
一个,将
key
存储为std::string
:
const char* SUFFIX = "suffix";
class widget{
public:
widget(const char* prefix) : key(std::string(prefix) + suffix), cls(key.c_str())
{}
private:
std::string key;
const important_class cls;
};
二,使用静态初始化函数,像这样:
const char* SUFFIX = "suffix";
class widget{
public:
widget(const char* prefix) : key(concat_(prefix, suffix)), cls(key)
{}
private:
const char* key;
const important_class cls;
static const char* concat_(const char* a, const char* b)
{
std::string val(a);
val += b;
char* ret = new char[val.size() + 1];
strcpy(ret, val.c_str());
return val;
}
};
乍一看你的问题像是理论测验,但后来我想起来可能有一个没有STL的嵌入式平台。
无论如何,你需要坚持使用老式的 C 风格函数:strlen、strcpy 和 strcat.
由于您使用的是类,因此我假设您的编译器也支持 operator new 。
在我编写最终代码之前,您需要执行以下步骤来连接字符串:
const char* key;
key = new char[strlen(prefix) + strlen(SUFFIX) + 1];
strcpy(key, prefix);
strcat(key, SUFFIX);
...
delete [] key;
幸运的是,strcpy 和 strcat 都返回了目的地。
这是您的代码的外观:
#include <string.h>
class widget {
public:
widget(const char* prefix)
: key(strcat(strcpy(new char[strlen(prefix) + strlen(SUFFIX) + 1], prefix), SUFFIX))
, cls(key) { };
private:
const char* key;
const important_class cls;
};
我没有调试这段代码,但它编译得很好,虽然它看起来很乱......:)
不要忘记在析构函数中释放缓冲区。
祝你好运!
如果你不是
std::string
的粉丝,你仍然可以制作你的c风格char*
构建器的自定义函数,并在构造函数中调用构建器。std::runtime_error(const char*)
已成功从其子类初始化,num::dividebyzero_error
std::runtime_error
std::exception
在任何情况下,err.what() 都会正确显示字符串。
// snprintf(char* result, size_t maxsize, const char* format, args...)
#include <iostream>
class num {
public:
int value;
num() : value(0) {}
num(int newvalue) : value(newvalue) {}
class dividebyzero_error : public std::runtime_error {
private:
const char* makemsg(int dividend) {
char* msg = (char*)malloc(128);
snprintf(msg, 128, "You should not divide %d into ZERO.", dividend);
return msg;
}
public:
dividebyzero_error(int dividend): std::runtime_error(makemsg(dividend)) {} // this works!
};
friend num operator/(const num &n1, const num &n2) {
if (n2.value == 0) throw dividebyzero_error(n1.value);
return num(n1.value / n2.value);
}
};
int main() {
num a(1234);
num b;
try {
num c = a / b;
std::cout << c.value << '\n';
} catch (std::exception &err) {
std::cout << err.what() << '\n';
}
}