3

我有自己的代表自定义字符串类的类。我正在使用 VS2012RC。我已经重载了我的类 CustomString 的一些运算符。

这是一些代码:

CustomString::CustomString(string setstr)
{           
    str = setstr;
}

CustomString::operator const char *()
{   
    return (this->str.c_str());
}

CustomString &CustomString::operator = (char *setstr)
{
    str = setstr;
    return *this;
}

我可以定义我的对象并像这样使用它:

CustomString str = "Test string";

我可以将结果打印为:

printf(str);

printf((string)(str).c_str());

printf((string)(str).data());

printf("%s\n",(string)(str).c_str());

printf("%s\n",(string)(str).data());

并且没有任何错误。

但如果我这样使用它:

printf("%s\n", str);

msvcr110d.dll 有异常(内存访问错误)

为什么printf(str)可以,但printf("%s\n",str)不行?

如何修改我的代码以使用printf("%s\n",str)

...

经过数小时的谷歌搜索,我发现显式转换 (string)、static_cast (str) 和 _str() 方法添加了一个以空字符结尾的字符:'\0';

我已将我的代码修改为:

printf("%s\n",str + '\0');

它成功了!

有什么方法可以修改我的自定义构造函数以添加一个以空字符结尾的字符串并使用以空字符结尾的字符传递一个正确的值来运行以下代码:

printf("%s\n",str);
4

4 回答 4

3

你不能(至少不能以便携的方式)。printf查看作为参数传递的对象并将其视为 a %s,它是一个 char 数组。您遇到未定义的行为。此外,传递给的参数可以printf说是无类型的。

为什么 printf(str) 没问题?

因为第一个参数是类型,并且是一个const char*. 隐式转换是通过您的运算符进行的。其余参数的行为不同。

我会改用cout和重载operator << (ostream&, const CustomString&)

不要这样做:

我说你不能,以便携的方式。对于像这样的课程

class CustomString
{
   char* str;
   //...
};

这可能会起作用,因为类在内存中的表示方式。但是,同样,它仍然是未定义的行为。

于 2012-08-22T09:04:02.913 回答
3

不要使用printf,它比 C++ 更像 C。相反,使用iostreams,它为您提供了一种工具来格式化您自己的自定义类并将其发送到文件或标准输出。

这是一个可能对您有用的快速(未经测试)示例:

std::ostream& operator<< (std::ostream &os, const CustomString& str)
{ 
    os << str.data();
    return os; 
} 

并且您可以通过执行类似的操作将自定义字符串打印到标准输出

CustomString str;
// put some text in the custom string, then:
std::cout << str << std::endl;
于 2012-08-22T09:05:48.297 回答
3

printf 定义为

int printf(char const *fmt, ...)

将类或结构传递给 ... 参数列表具有未定义的行为,可能会工作或崩溃,或者只是随机做一些事情(我已经看过所有 3 个),具体取决于类和编译器。

printf(str)

需要一个 char *,编译器发现你有一个合适的转换运算符,所以它调用它。请注意,这是非常狡猾的,因为您不知道 str 是否可能包含 % 。

所以,你确实想要printf("%s", str),但正如你所说,那是行不通的。一些编译器会给你一个警告(尽管在我看来,由 gcc 产生的“警告:这将崩溃”并不是经过深思熟虑的),所以你必须强制它被强制转换为字符串。所以,你最好的解决方案是自己显式地转换它,

printf("%s", static_cast<char const *>(str));

我不确定您所拥有的所有示例需要多少代码,因为其中大多数将涉及从您的自定义字符串构造一个 std::string,然后输出它,然后删除 std::string .

于 2012-08-22T10:44:12.693 回答
1

你必须使用printf("%s\n", str.c_str());. %s需要一个 char 数组,而你给了它一个CustomString不同的对象。您必须通过调用c_str()函数从字符串中获取字符数组。

于 2012-08-22T09:03:58.980 回答