在VS2015和VS2017上,此编译没有警告,并生成无法捕获的访问冲突并导致应用程序崩溃.显然,int 0被静默转换为空指针,然后假定它指向一个字符串,从而崩溃.
#include <string>
#include <iostream>
void crash(const std::string& s) {}
int main()
{
try
{
crash(0);
}
catch (const std::exception& ex)
{
// never gets here!
std::cout << "got" << ex.what() << std::endl;
}
}
Run Code Online (Sandbox Code Playgroud)
如何从这样的异常中捕获并恢复?如果我从函数参数中删除const它不会编译 - 所以这可能是防止用户滥用的一种方法,但是我会失去const提供的保护,或者我会吗?编写避免此问题的原型的最佳做法是什么?
假设我有自定义字符串类:
class my_string : public std::string
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
我想创建一个模板化函数,my_string
默认情况下接受这两个函数:
template <typename TString = my_string>
TString do_something(const TString& input)
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
但当我打电话给:
auto result = do_something("abcdef");
Run Code Online (Sandbox Code Playgroud)
它(当然)打电话do_something<char[7]>()
.如何在do_something<my_string>
没有明确指定类型的情况下强制它调用(即写入do_something("abcdef")
,不是do_something<my_string>("abcdef")
)?
std::string
(因为大多数 - 如果不是全部 - 标准类)没有任何虚拟方法,因此创建具有虚拟方法的继承类将导致 UB(最有可能是析构函数)。(如果我错了,请纠正我)。
我认为没有多态的继承是可以的,直到我在网上阅读了这个主题。
例如,在这个答案中:为什么不应该从 c++ std 字符串类派生?有人反对这种做法。主要原因似乎是切片问题,当派生对象被传递给函数代替std::string
参数时,它会抑制添加的功能,从而使非多态性不合逻辑。如果想要扩展string
. 我同意所有这些,特别是因为我提倡自由函数而不是单一类。
话虽如此,我认为我发现了一种情况,我认为实际上可以保证从std::string
. 我将首先展示我想要解决的问题,然后我将展示为什么我认为继承自是std::string
最好的解决方案。
当将用于调试目的的函数从 C 移植到 C++ 时,我意识到无法在 C++ 中创建格式化字符串(不使用类似 C 的字符串函数,例如sprintf
)。IE:
C 版本:void someKindOfError(const char *format, ...);
这将被称为:
someKindOfError("invalid argument %d, size = %d", i, size);
Run Code Online (Sandbox Code Playgroud)
C++ 版本:void someKindOfError(const std::string &message);
将其调用为类似的效果将是:
std::stringstream ss;
ss << "invalid argument " << i << ", size = " << size;
someKindOfError(ss.str());
Run Code Online (Sandbox Code Playgroud)
这不能是单行,因为<< …
我现在只使用c ++大约一个月了,我想知道是否有可能为类似字符串的东西创建自己的自定义函数.例如,要找到你所做的字符串的大小stringname.size()
但是,如果我想创建一个函数stringname.customfunction()
,那么我可以决定做什么customfunction()
.我想这样做,所以我可以创建一个.toLower()函数,将整个字符串转换为更低.我很抱歉,如果这是一个奇怪的问题,但任何帮助将不胜感激.
我在书中看到了这个例子:
class Test: private std::string
{
public:
Test():std::string("How?")
{
}
};
int main(int argc, char** argv)
{
Test t;
std::cout<<(std::string&)t<<std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我不知道当我对类名称进行类型化时它是如何打印"如何"的?是因为运营商?但我知道,当你进行私有继承时,公共和受保护的变量和方法将被视为"私有".
所以我的问题是,它是如何打印"如何"?
编辑:
那么谁持有字符串值"如何"以及它是如何打印的?因为它是通过类型转换打印的.
我有一个MFC源文件,我需要在Qt下编译.此文件使用MFC/ATL CString.具体来说,它使用CString作为iostream :: open()的参数.我编写了一个继承自QString的CString类,以便我可以使用大多数QStrings的功能.
我主要担心的是我无法让我的CString实现在调用iostream :: open()的地方工作:
这是我的班级声明:
class CString : public QString {
public:
CString() : QString() {}
CString(const QString& other) : QString(other) {}
CString(const CString& other) : QString(other) {}
CString(_In_opt_z_ const XCHAR* pszSrc) : QString( pszSrc ) { *this = pszSrc; }
CString(const char* pszSrc) : QString( pszSrc ) {}
...
}
Run Code Online (Sandbox Code Playgroud)
并且,这是使用CString的代码的一部分:
ofstream outfile;
CString Path("dump.txt");
outfile.open(Path);
Run Code Online (Sandbox Code Playgroud)
错误是:
没有用于调用'std :: basic_ofstream> :: open(CString&)'的匹配函数
在"正常"情况下,我会做一些像:
outfile.open(Path.toStdString().c_str());
Run Code Online (Sandbox Code Playgroud)
但是,这不是一种选择.未授权修改原始代码.:(
有没有办法做到这一点,或者我将不得不使用Microsoft在cstringt.h中使用的相同,更复杂和冗长的代码来重建类?
谢谢
当我正在开发一个涉及用给定语言定义句子的项目时,我惊讶地发现std::string
析构函数不是虚拟的.这使得专门化这个类变得更加困难(我必须创建一个包装器).为什么标准委员会决定让这个课程不虚拟?
在/usr/lib64/gcc/x86_64-pc-linux-gnu/4.5.3/include/g++-v4/bits/basic_string.h中,我们有:
template<typename _CharT, typename _Traits, typename _Alloc>
class basic_string
{
...
/**
* @brief Destroy the string instance.
*/
~basic_string()
{ _M_rep()->_M_dispose(this->get_allocator()); }
Run Code Online (Sandbox Code Playgroud) 最近,我一直想要定义std :: string的子类spstring.它在spstr.h中声明:
#include <cctype>
#include <string>
#include <algorithm>
#include <sstream>
#include <stdint.h>
#include <xstring>
class spstring : public std::string {
public:
spstring(std::string s):std::string(s){} //Declare the constructor
int stoi(); //Declare stoi
spstring Spstring(std::string s); ////Declare mandatory conversion function
};
spstring spstring::Spstring(std::string s)
{
spstring spstr(s);
return(spstr);
}
Run Code Online (Sandbox Code Playgroud)
但是,在main.cpp中测试时:
spstring byteaddstr(std::string(argv[4])); //convertchar* to spstring
int byteadd;
byteadd=byteaddstr.stoi(); //call byteaddstr.stoi
Run Code Online (Sandbox Code Playgroud)
它没有被遵守:
错误C2228:".stoi"的左边必须有class/struct/union
听起来很奇怪,因为byteaddstr确实是spstring的一个实例,为什么不能调用它的成员函数呢?
我想在字符串类中添加一个新的成员函数"charReplace".该函数将用一个字符替换一个字符的所有出现.所以我准备了一个示例代码.
#include <iostream>
#include <string>
std::string string::charReplace(char c1, char c2) { //error in this line
while(this->find(c1) != std::string::npos) {
int c1pos = this->find(c1); //find the position of c1
this->replace(c1pos, 1, c2); //replace c1 with c2
}
return *this;
}
int main() {
std::string s = "sample string";
s.charReplace('s', 'm') /* replace all s with m */
std::cout << s << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
但它没有用.我在编译时在第4行中收到以下错误.
错误:'string'没有命名类型
我知道通过创建非成员函数可以很容易地得到相同的结果.但我想用成员函数来做.那么,有没有办法在c ++中做到这一点?
PS我仍然是c ++的新手.我一直在使用它几个月.所以,请尽量让您的答案易于理解.