英文:
C++ inheritance: string construction in constructor
问题
I'm learning C++ at the moment and implementing a sample program for exception handling right now. The main program implements a number system with arbitrary bases. I made a class nums_exception : public std::exception
with function virtual const char *what();
.
#include <stdexcept>
#include <sstream>
class Nums
{
public:
Nums() {}
unsigned int getBase() { return 2; }
};
class nums_exception: public std::exception
{
public:
nums_exception(Nums* obj, std::string errortext);
virtual ~nums_exception();
virtual const char *what() const noexcept;
const Nums *failObj();
private:
std::string errortext;
Nums *obj;
};
nums_exception::nums_exception(Nums *obj, std::string errortext)
: errortext(errortext)
, obj(obj)
{
}
nums_exception::~nums_exception() = default;
const char *nums_exception::what() const noexcept
{
if (this->errortext.size() == 0)
{
return "Nums exception!";
}
else
{
std::stringstream ret;
ret << "Nums exception at "
<< obj
<< " :"
<< this->errortext;
return ret.str().c_str();
}
}
// Now i derived nums_bad_digit, which should look like this:
class nums_bad_digit: public nums_exception
{
public:
nums_bad_digit(Nums* obj, uint base, char digit);
virtual ~nums_bad_digit() override;
static std::string ERRORTEXT(Nums *obj, char digit);
private:
std::string errortext;
const uint base;
Nums *obj;
};
inline std::string nums_bad_digit::ERRORTEXT(Nums *obj, char digit)
{
return std::string(std::to_string(digit) + " not in alphabet for base " +
std::to_string(obj->getBase()) + '.');
}
nums_bad_digit::nums_bad_digit(Nums *obj, uint base, char digit)
: nums_exception(obj, ERRORTEXT(obj, digit))
, base(base)
{
}
nums_bad_digit::~nums_bad_digit() = default;
int main()
{
Nums n;
throw nums_bad_digit(&n, 42, 'x');
}
Here I tried to reach my goal using a static method.
I want to construct a ready-to-show errormessage, which says why exactly I threw this exception, and then pass it to the nums_exception
constructor. As an example, nums_bad_digit::what() should return Nums_expection at 0x777fff: 'Q' not in alphabet for base 16.
I also tried a compiler macro... But whatever I try - writing it as normal code works fine. But when I want to pass the string to the nums_exception
constructor, it will always get an empty string.
英文:
I'm learning C++ at the moment and implementing a sample program for exception handling right now.
The main program implements a number system with arbitrary bases.
I made a class nums_exception : public std::exception
with function virtual const char *what();
#include <stdexcept>
#include <sstream>
class Nums
{
public:
Nums() {}
unsigned int getBase() { return 2; }
};
class nums_exception: public std::exception
{
public:
nums_exception(Nums* obj, std::string errortext);
virtual ~nums_exception();
virtual const char *what() const noexcept;
const Nums *failObj();
private:
std::string errortext;
Nums *obj;
};
nums_exception::nums_exception(Nums *obj, std::string errortext)
: errortext(errortext)
, obj(obj)
{
}
nums_exception::~nums_exception() = default;
const char *nums_exception::what() const noexcept
{
if (this->errortext.size() == 0)
{
return "Nums exception!";
}
else
{
std::stringstream ret;
ret << "Nums exception at "
<< obj
<< " :"
<< this->errortext;
return ret.str().c_str();
}
}
// Now i derived nums_bad_digit, which should look like this:
class nums_bad_digit: public nums_exception
{
public:
nums_bad_digit(Nums* obj, uint base, char digit);
virtual ~nums_bad_digit() override;
static std::string ERRORTEXT(Nums *obj, char digit);
private:
std::string errortext;
const uint base;
Nums *obj;
};
inline std::string nums_bad_digit::ERRORTEXT(Nums *obj, char digit)
{
return std::string(std::to_string(digit) + " not in alphabet for base " +
std::to_string(obj->getBase()) + '.');
}
nums_bad_digit::nums_bad_digit(Nums *obj, uint base, char digit)
: nums_exception(obj, ERRORTEXT(obj, digit))
, base(base)
{
}
nums_bad_digit::~nums_bad_digit() = default;
int main()
{
Nums n;
throw nums_bad_digit(&n, 42, 'x');
}
Here I tried to reach my goal using a static method.
I want to construct a ready-to-show errormessage, which says why exactly I threw this exception, and then pass it to the nums_exception
constructor. As example, nums_bad_digit::what() should return
Nums_expection at 0x777fff: 'Q' not in alphabet for base 16.
I also tried a compiler macro... But whatever I try - writing it as normal code works fine. But when I want to pass the string to the nums_exception
constructor, it will always get an empty string.
答案1
得分: 1
-
参数应该会被提升为
int
,其值为输入字符的 ASCII 码(或您所使用的编码)。因此'x'
会变成“120”
。这不是您想要的结果。您应该使用
std::string(1, digit)
代替。阅读您使用的函数的文档!至少要单独测试程序的单元。
-
what()
返回一个const char*
,但它所指向的数据已经无效。stringstream 是局部的,字符串是临时的,所以这个指针会立即悬空。我建议在构造函数中生成完整的字符串,并将其作为成员存储,以便它在异常对象存在的时间内保持有效。
所以,这样的代码:
nums_exception::nums_exception(Nums *obj, std::string errortext)
: obj(obj)
{
if (errortext.size() == 0)
{
this->errortext = "Nums exception!";
}
else
{
std::stringstream ret;
ret << "Nums exception at "
<< obj
<< " :"
<< errortext;
this->errortext = ret.str();
}
}
以及这样的代码:
const char *nums_exception::what() const noexcept
{
return errortext.c_str();
}
还有这样的代码:
inline std::string nums_bad_digit::ERRORTEXT(Nums *obj, char digit)
{
return std::string(1, digit) + " not in alphabet for base " +
std::to_string(obj->getBase()) + '.';
}
(在线演示)
英文:
There are several problems here.
-
std::to_string
does not take achar
.The argument would presumably get promoted to
int
, with the value being the ASCII code (or whatever you're using) of the input. So'x'
becomes"120"
. Not what you wanted.You should use
std::string(1, digit)
instead.Read the documentation for the functions that you use! At the very least, test the units of your program in isolation.
-
what()
returns aconst char*
, but the data it points to is dead.The stringstream was local, and the string was temporary, so this pointer is immediately dangling. I'd generate the full string in the constructor instead, and store it as a member so that it survives for as long as the exception object does.
So, this:
nums_exception::nums_exception(Nums *obj, std::string errortext)
: obj(obj)
{
if (errortext.size() == 0)
{
this->errortext = "Nums exception!";
}
else
{
std::stringstream ret;
ret << "Nums exception at "
<< obj
<< " :"
<< errortext;
this->errortext = ret.str();
}
}
and this:
const char *nums_exception::what() const noexcept
{
return errortext.c_str();
}
and this:
inline std::string nums_bad_digit::ERRORTEXT(Nums *obj, char digit)
{
return std::string(1, digit) + " not in alphabet for base " +
std::to_string(obj->getBase()) + '.';
}
(live demo)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论