class String:public std :: string {}; ???? [英] class String : public std::string {}; ????

查看:67
本文介绍了class String:public std :: string {}; ????的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

你好,


有人可以向我解释为什么标准召集人选择键入def

std :: string而不是从std :: basic_string<得到它; char,...>?


结果当然是,实际上无法转发声明

std :: string。 (是的我知道有些库有一个string_fwd.h标题,

但这不是便携式的。)


那说,有什么真正的原因为什么我不能从std :: string派生一个空的

String类?会有隐藏的惊喜吗?当我理解它时,String没有自己的成员变量这一事实意味着非虚拟std :: string析构函数不是问题。


尽管如此,我很警惕,因为我已经听到了很多关于''std :: string不是

的设计来源于''。然而,没有人向我解释这种

a声明背后的理由。


以下示例代码似乎工作正常。

祝你好运,

Angus


#ifndef FWD_DECLARABLE_STRING_H

#define FWD_DECLARABLE_STRING_H

>
#include< string>


struct String:public std :: string {

typedef std :: string base_type;


String(){}

String(base_type const& other)

:base_type(other){}

explicit String(allocator_type const& al)

:base_type(al){}

String(String const& other,size_type off,size_type count = npos )

:base_type(其他,关闭,计数){}

字符串(字符串const& other,size_type off,size_type count,

allocator_type const& al)

:base_type(other,off,count,al){}

String(value_type const * ptr,size_type count)

:base_type(ptr,count){}

String(value_type const * ptr,size_type count,allocator_type const& al)

:base_type(ptr,count,al){}

String(value_type const * ptr)

:base_type(ptr){ } $ / $
String(value_type const * ptr,allocator_type const& al)

:base_type(ptr,al){}

String(size_type count,value_type ch)

:base_type(count,ch){}

字符串(size_type count,value_type ch,allocator_type const& al)

:base_type(count,ch,al){}

模板< typename InIt>

字符串(首先是InIt,最后是InIt)

:base_type(first,last){}

template< typename InIt>

String(InIt first,InIt last,allocator_type const& al)

:base_type(first,last,al){}


String& operator =(value_type const * ptr)

{base_type :: operator =(ptr); }

String& operator =(value_type ch)

{base_type :: operator =(ch); }

};


#endif // FWD_DECLARABLE_STRING_H


#include< iostream>


int main()

{

String const angus =" angus";

std :: string const jmarc =" jmarc";

String test1;

std :: string test2;


//分配标准::字符串到字符串

test1 = jmarc;

std :: cout<< test1 << test1<< std :: endl;


//将字符串分配给std :: string

test2 = angus;

std: :cout<< test2 << test2<< std :: endl;


//将字符串赋给字符串(隐式赋值运算符)

test1 = angus;

std :: cout<< test1 << test1<< std :: endl;


//隐式复制c-tor;

字符串const test3 = angus;

std :: cout<< test3 << test3<< std :: endl;


//从字符串复制构造std :: string

std :: string test4 = angus;

std :: cout<< test4 << test4<< std :: endl;


返回0;

}

解决方案

Angus Leeming< an *********** @ btopenworld.com>写道:

你好,

有人可以向我解释为什么标准召集人选择输入stde ::
std :: string而不是从std派生出来:: basic_string< char,...>?

结果当然是实际上无法转发声明
std :: string。 (是的,我知道有些库有一个string_fwd.h标题,
但这不是便携式的。)

那就是说,有什么理由我无法得到一个否则是空的
来自std :: string的字符串类?


有两个问题。


(a)没有虚拟析构函数。这意味着当指向的对象实际上是一个

derived_from_string时,你不能安全地调用删除

a指向字符串的指针。


(b)它不是为多态性而设计的。 (像大多数标准的

库一样。)公共继承通常用于

多态。注意(a)是(b)的症状。


如果你以某种方式知道你永远不会使用derived_from_string

多态,你就赢了''遇到问题。


但是,在继续之前,尝试使用私有继承和

几个使用良好的使用语句。这更安全。


会有任何隐藏的惊喜吗?


见上文。此外,如果人们*可以*使用你的

derived_from_string类型进行多态使用,他们经常会这样做。

据我所知,String没有成员变量这一事实
它本身意味着非虚拟std :: string析构函数不是问题。



[snip]


这与它无关。在指向字符串的指针上调用delete

是未定义的行为,如果它实际上指向

derived_from_string,无论derived_from_string是否具有

成员变量它本身。




" Angus Leeming" <一个*********** @ btopenworld.com>在消息新闻中写道:bj ********** @ hercules.btinternet.com ...


那就是说有什么真正的理由吗我不能从std :: string派生出一个空的
String类?会有隐藏的惊喜吗?正如我理解的那样,String没有自己的成员变量这一事实意味着非虚拟std :: string析构函数不是问题。




是什么让你觉得这不是问题?从没有虚拟析构函数的指向其基类的指针中删除
a派生对象是未定义的行为。

导出的析构函数不是没关系做什么或那个

在派生类中没有数据成员。


Ron Natalie写道:
< blockquote class =post_quotes>
Angus Leeming <一个*********** @ btopenworld.com>在消息中写道
新闻:bj ********** @ hercules.btinternet.com ...


那说,有没有为什么我不能从std :: string派生一个空的
String类?会有隐藏的惊喜吗?正如我理解的那样,String没有自己的成员变量
意味着非虚拟std :: string析构函数不是问题。


析构函数的指向其基类的指针中删除派生对象是未定义的行为。导出的析构函数不做任何事情或派生类中没有数据成员都没关系。




非常感谢对你们两个人的清楚解释。我将把你的

参数提交给项目主持人,他们会立即启动我建议的使用

String触摸;-)


再次感谢,

Angus


Hello,

Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_string<char, ...>?

The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)

That said, is there any real reason why I can''t derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own means
that the non-virtual std::string destructor is not an issue.

Nonetheless, I''m wary because I have heard so much about ''std::string is not
designed to be derived from''. Nobody has explained the rationale behind such
a statement to me however.

Below is sample code that appears to work just fine.

Best regards,
Angus

#ifndef FWD_DECLARABLE_STRING_H
#define FWD_DECLARABLE_STRING_H

#include <string>

struct String : public std::string {
typedef std::string base_type;

String() {}
String(base_type const & other)
: base_type(other) {}
explicit String(allocator_type const & al)
: base_type(al) {}
String(String const & other, size_type off, size_type count = npos)
: base_type(other, off, count) {}
String(String const & other, size_type off, size_type count,
allocator_type const & al)
: base_type(other, off, count, al) {}
String(value_type const * ptr, size_type count)
: base_type(ptr, count) {}
String(value_type const * ptr, size_type count, allocator_type const & al)
: base_type(ptr, count, al) {}
String(value_type const * ptr)
: base_type(ptr) {}
String(value_type const * ptr, allocator_type const & al)
: base_type(ptr, al) {}
String(size_type count, value_type ch)
: base_type(count, ch) {}
String(size_type count, value_type ch, allocator_type const & al)
: base_type(count, ch, al) {}
template <typename InIt>
String(InIt first, InIt last)
: base_type(first, last) {}
template <typename InIt>
String(InIt first, InIt last, allocator_type const & al)
: base_type(first, last, al) {}

String & operator=(value_type const * ptr)
{ base_type::operator=(ptr); }
String & operator=(value_type ch)
{ base_type::operator=(ch); }
};

#endif // FWD_DECLARABLE_STRING_H

#include <iostream>

int main()
{
String const angus = "angus";
std::string const jmarc = "jmarc";
String test1;
std::string test2;

// Assign a std::string to a String
test1 = jmarc;
std::cout << "test1 " << test1 << std::endl;

// Assign a String to a std::string
test2 = angus;
std::cout << "test2 " << test2 << std::endl;

// Assign a String to a String (implicit assignment operator)
test1 = angus;
std::cout << "test1 " << test1 << std::endl;

// Implicit copy c-tor;
String const test3 = angus;
std::cout << "test3 " << test3 << std::endl;

// Copy construct a std::string from a String
std::string test4 = angus;
std::cout << "test4 " << test4 << std::endl;

return 0;
}

解决方案

Angus Leeming <an***********@btopenworld.com> writes:

Hello,

Could someone explain to me why the Standard conveners chose to typedef
std::string rather than derive it from std::basic_string<char, ...>?

The result of course is that it is effectively impossible to forward declare
std::string. (Yes I am aware that some libraries have a string_fwd.h header,
but this is not portable.)

That said, is there any real reason why I can''t derive an otherwise empty
String class from std::string?
There are two issues.

(a) No virtual destructor. This means you can''t safely call delete on
a pointer to string when the object pointed to is in fact a
derived_from_string.

(b) It isn''t designed for polymorphism. (Like most of the standard
library.) Public inheritance is usually used for
polymorphism. Note (a) is a symptom of (b) .

If you somehow know you''ll never use the derived_from_string
polymorphically, you won''t encounter problems.

However, before proceeding, try private inheritance combined with a
few well-placed using statements. That is safer.

Will there be any hidden surprises?
See above. Further, if people *can* make polymorphic use of your
derived_from_string type, they all too often will.
As I understand it, the fact that String has no member variables of
its own means that the non-virtual std::string destructor is not an
issue.


[snip]

This has nothing to do with it. Calling delete on a pointer to string
is undefined behavior if it in fact points to a
derived_from_string, regardless of whether derived_from_string has
member variables of its own.



"Angus Leeming" <an***********@btopenworld.com> wrote in message news:bj**********@hercules.btinternet.com...


That said, is there any real reason why I can''t derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own means
that the non-virtual std::string destructor is not an issue.



What makes you think it''s not an issue? It is undefined behavior to delete
a derived object from a pointer to its base class without a virtual distructor.
It doesn''t matter that the derived destructor doesn''t do anything or that there
are no data members in the derived class.


Ron Natalie wrote:


"Angus Leeming" <an***********@btopenworld.com> wrote in message
news:bj**********@hercules.btinternet.com...


That said, is there any real reason why I can''t derive an otherwise empty
String class from std::string? Will there be any hidden surprises? As I
understand it, the fact that String has no member variables of its own
means that the non-virtual std::string destructor is not an issue.



What makes you think it''s not an issue? It is undefined behavior to delete
a derived object from a pointer to its base class without a virtual
distructor. It doesn''t matter that the derived destructor doesn''t do
anything or that there are no data members in the derived class.



Many thanks to both of you for the clear explanation. I shall put your
arguments to the project moderator who will promptly boot my proposed use of
String into touch ;-)

Thanks again,
Angus


这篇关于class String:public std :: string {}; ????的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆