C++继承:构造函数中的字符串构造

huangapple go评论79阅读模式
英文:

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 &lt;stdexcept&gt;
#include &lt;sstream&gt;
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-&gt;errortext.size() == 0)
{
return &quot;Nums exception!&quot;;
}
else
{
std::stringstream ret;
ret &lt;&lt; &quot;Nums exception at &quot;
&lt;&lt; obj
&lt;&lt; &quot; :&quot;
&lt;&lt; this-&gt;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) + &quot; not in alphabet for base &quot; +
std::to_string(obj-&gt;getBase()) + &#39;.&#39;);
}
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(&amp;n, 42, &#39;x&#39;);
}

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

  1. std::to_string 不接受 char 参数。

    参数应该会被提升为 int,其值为输入字符的 ASCII 码(或您所使用的编码)。因此 'x' 会变成 “120”。这不是您想要的结果。

    您应该使用 std::string(1, digit) 代替。

    阅读您使用的函数的文档!至少要单独测试程序的单元。

  2. 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.

  1. std::to_string does not take a char.

    The argument would presumably get promoted to int, with the value being the ASCII code (or whatever you're using) of the input. So &#39;x&#39; becomes &quot;120&quot;. 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.

    &nbsp;

  2. what() returns a const 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.

    &nbsp;

So, this:

nums_exception::nums_exception(Nums *obj, std::string errortext)
: obj(obj)
{
if (errortext.size() == 0)
{
this-&gt;errortext = &quot;Nums exception!&quot;;
}
else
{
std::stringstream ret;
ret &lt;&lt; &quot;Nums exception at &quot;
&lt;&lt; obj
&lt;&lt; &quot; :&quot;
&lt;&lt; errortext;
this-&gt;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) + &quot; not in alphabet for base &quot; +
std::to_string(obj-&gt;getBase()) + &#39;.&#39;;
}

(live demo)

huangapple
  • 本文由 发表于 2020年1月4日 00:24:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/59581951.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定