如何进行类扩展

GKatHere 2017-01-20 08:40:31
如题:如何进行类扩展
如:想要向 std::string 增加一 left函数

// std::string 基类
class A : public std::string
{
std::string left(long n)
{
retrun std::string(begin(), begin() +n);
}
}
// 使用
std::string str(abc);
std::string str2 = ( (A*)(&str))->left(2); // 这样可以,但显得丑陋
...全文
281 14 打赏 收藏 转发到动态 举报
写回复
用AI写文章
14 条回复
切换为时间正序
请发表友善的回复…
发表回复
GKatHere 2017-01-22
  • 打赏
  • 举报
回复
确实,stringXX(...) :std::string(...){}; 看上去挺美。使用上不行。 试了下继承构造函数,晕了,VS2010对c++11的这特性未持:

class stringXX :public std::string
{
public:
  using string::basic_string<char, char_traits<char>, allocator<char> >;		//	声明OK,但并未继承构造函数
  using string::cend;

};
class AA
{
public: AA(int){};
};
class AAX :public AA
{
public:
	using AA::AA;
};
int main()
{
	AAX aax(1);				// ERROR
	stringXX xx("dddd");	// ERROR
}
ztenv 版主 2017-01-22
  • 打赏
  • 举报
回复
面向对象的“封-闭原则”
几罗星人 2017-01-22
  • 打赏
  • 举报
回复
引用 10 楼 GKatHere 的回复:
确实,stringXX(...) :std::string(...){}; 看上去挺美。使用上不行。 试了下继承构造函数,晕了,VS2010对c++11的这特性未持:

class stringXX :public std::string
{
public:
  using string::basic_string<char, char_traits<char>, allocator<char> >;		//	声明OK,但并未继承构造函数
  using string::cend;

};
class AA
{
public: AA(int){};
};
class AAX :public AA
{
public:
	using AA::AA;
};
int main()
{
	AAX aax(1);				// ERROR
	stringXX xx("dddd");	// ERROR
}
好吧,2010有点古老了,现在都17年了。2010刚刚开始支持C++11,但是支持的不好,13开始比较正常,15基本上都能支持了
colorfulcode 2017-01-22
  • 打赏
  • 举报
回复
楼主需要C#那种 扩展方法 ,但C++毕竟不是C#,虽然C++可以模拟出扩展函数,但是终究比不上C#那样的优雅。 so,楼主还是放弃扩展吧,老老实实写个公共函数来处理吧
几罗星人 2017-01-21
  • 打赏
  • 举报
回复
语句从基类string继承所有构造函数。并且据说如果派生类中没有使用的构造函数不会生成代码。

using string::string;
引用 7 楼 GKatHere 的回复:
继承唯一缺点就是需要重写所有基类的构造函数,以方便使用。 当然也可以以引用构造,不过这样代码有一点膨胀

class stringXX :public std::string
{
public:
  //stringXX(...) :std::string(__ARGS__){};   // ERROR, 不可转发
  stringXX(const std::string& r) :std::string(r){};  

};
用起来的复杂度是一样的,性能也很是一样的。最简洁的办法还是用继承,然后直接使用派生类。
你这个代码是不对的,不对的地方有三个。 一、宏名不是__ARGS__,而是__VA_ARGS__ 二、__VA_ARGS__这个只能用在宏定义中,也就是#define……中 三、即使这样能转发,从原理上说string的构造函数也不可能取出参数,也无法知道参数的数量。先说参数数量比较好理解,c语言的printf知道吧,有没有想过为什么需要第一个参数——格式控制字符串,例如"%d%s%f",实际上格式控制字符串告诉printf函数,后面变参的部分有3个参数,分别是整形(int),字符串,单精度浮点(float)。所以没有一个参数来说明变参部分具体有多少个参数,谁都不知道。接着就是函数要处理变参数,就必须要使用几个宏,分别是 va_start,va_list,va_arg,va_end。这几个宏是通过格式化控制字符串的给出的类型决定要读取多少个字节的内容并转换为什么类型的 综上,这种转发虽然看上去合理,但是从原理上不行。直接用构造函数继承就可以了
几罗星人 2017-01-21
  • 打赏
  • 举报
回复
引用 7 楼 GKatHere 的回复:
继承唯一缺点就是需要重写所有基类的构造函数,以方便使用。 当然也可以以引用构造,不过这样代码有一点膨胀
其实根本不需要,使用C++11的新语法构造函数继承就可以了

#include <string>
using namespace std;

class X :public string
{
public:
	using string::string;
};

int main()
{
	X x("123456");

	return 0;
}
GKatHere 2017-01-21
  • 打赏
  • 举报
回复
继承唯一缺点就是需要重写所有基类的构造函数,以方便使用。 当然也可以以引用构造,不过这样代码有一点膨胀

class stringXX :public std::string
{
public:
  //stringXX(...) :std::string(__ARGS__){};   // ERROR, 不可转发
  stringXX(const std::string& r) :std::string(r){};  

};
int main()
{
	std::string strORG("abcde");
	OutputDebugStringA(strORG.c_str());
	strORG += "ddd";

	stringXX strXX(std::string("abcde"));
	OutputDebugStringA(strXX.c_str());
	strXX += "ddd";
}
引用 4 楼 JiLuoXingRen 的回复:
[quote=引用 3 楼 GKatHere 的回复:] int main() { std::string str("000"); stringX(str).format("%d", 123456789); printf(str.c_str()); std::wstring strW(L"0000"); wstringX(strW).format(L"%d", 123456789); wprintf(strW.c_str()); printf("getchar()"); getchar(); } [/code]
与其这样搞,那跟这样有什么不同?

void format(string& s, int n)
{
      // 进行处理
}

int main()
{
    std::string str("000");
    format(str, 123456789);
    // ……
}
用起来的复杂度是一样的,性能也很是一样的。最简洁的办法还是用继承,然后直接使用派生类。[/quote]
GKatHere 2017-01-21
  • 打赏
  • 举报
回复
改源代码不可行。 #define 红色危险。 嗯,left 可用 substr. 想想,试了下has-a, 在release下无消耗

template<class _Elem,	class _Traits,	class _Ax>
class basic_stringX
{
public:
	typedef basic_string<_Elem, _Traits,_Ax > value_type;

public:
	value_type& v;

	basic_stringX(value_type& v_)	:v(v_){};

public:
	long format(const _Elem* fmt, ...)
	{
		v.clear();
		const BOOL bW =std::tr1::is_same<wchar_t, _Elem>::value;

		long sz=0;
		if(bW)	sz =_vscwprintf((const wchar_t*)fmt, args);			//	能运行,release下无消耗,不过丑陋
		else sz =_vscprintf((const char*)fmt, args);

		if (sz >0)
		{
			va_list args;
			va_start( args, fmt );
			v.resize(sz +1);

			if(bW) _vsnwprintf_s((wchar_t*)&v[0],  (sz +1) *sizeof(v[0]), sz +1, (const wchar_t*)fmt, args );	//	能运行,release下无消耗,不过丑陋
			else _vsnprintf_s((char*)&v[0],  (sz +1) *sizeof(v[0]), sz +1, (const char*)fmt, args );
			
			v.resize(sz);
			va_end ( args );
		}
		return sz;
	};
};
typedef basic_stringX<char, char_traits<char>, allocator<char> > stringX;
typedef basic_stringX<wchar_t, char_traits<wchar_t>, allocator<wchar_t> > wstringX;

int main()
{
	std::string str("000");
	stringX(str).format("%d", 123456789);
	printf(str.c_str());

	std::wstring strW(L"0000");
	wstringX(strW).format(L"%d", 123456789);
	wprintf(strW.c_str());


	printf("getchar()");
	getchar();
}
引用 1 楼 ipqtjmqj 的回复:
要么直接改源码,要么只能用预处理器了,但比较危险, 见http://ideone.com/dnjbwj
引用 2 楼 JiLuoXingRen 的回复:
[quote=引用 楼主 GKatHere 的回复:]

// std::string 基类
class A  : public std::string 
{
   std::string left(long n)
    {
     retrun std::string(begin(), begin() +n);
   }
}
// 使用
 std::string  str(abc);
 std::string  str2 = ( (A*)(&str))->left(2);    // 这样可以,但显得丑陋
首先这个“使用”本身就有问题,只添加一个函数还没什么,但是如果有数据成员你的这个使用方法就不行了,是访问不到数据成员的。 所以这种拓展不可行,一个办法像楼上上说的改string类的代码,第二个就是将要用有left函数的string类的地方改用类A。 附: 你的left函数【【【就是】】】如题目所给的实现的吗?就是截取字符串的前多少个字符? 如果是的话用string类的substr函数就行了: [/quote]
几罗星人 2017-01-21
  • 打赏
  • 举报
回复
引用 5 楼 jianwen0529 的回复:
首先,string 析构函数是非虚拟的,表明sting不希望被用户当做基类 因此继承sting类是一个危险的行为 再来,你修改标准库代码,除非你代码只希望自己用 否则会让别人看得莫名其妙 这种需求你直接写个专门处理sting的库就好了啊
话虽如此,但是如果不做派生类指针到父类指针的转换,就不会出现派生类析构函数没有被调用的问题。如果,自己用就饿没什么问题。 事实上,你既然去翻了string的源代码,不妨去看看它的基类_String_alloc(string类是typedef的basic_string,basic_string继承自_String_alloc)的源代码,你会发现_String_alloc的析构函数也不是虚的
幻夢之葉 2017-01-21
  • 打赏
  • 举报
回复
首先,string 析构函数是非虚拟的,表明sting不希望被用户当做基类 因此继承sting类是一个危险的行为 再来,你修改标准库代码,除非你代码只希望自己用 否则会让别人看得莫名其妙 这种需求你直接写个专门处理sting的库就好了啊
几罗星人 2017-01-21
  • 打赏
  • 举报
回复
引用 3 楼 GKatHere 的回复:
int main() { std::string str("000"); stringX(str).format("%d", 123456789); printf(str.c_str()); std::wstring strW(L"0000"); wstringX(strW).format(L"%d", 123456789); wprintf(strW.c_str()); printf("getchar()"); getchar(); } [/code]
与其这样搞,那跟这样有什么不同?

void format(string& s, int n)
{
      // 进行处理
}

int main()
{
    std::string str("000");
    format(str, 123456789);
    // ……
}
用起来的复杂度是一样的,性能也很是一样的。最简洁的办法还是用继承,然后直接使用派生类。
几罗星人 2017-01-20
  • 打赏
  • 举报
回复
引用 楼主 GKatHere 的回复:

// std::string 基类
class A : public std::string
{
std::string left(long n)
{
retrun std::string(begin(), begin() +n);
}
}
// 使用
std::string str(abc);
std::string str2 = ( (A*)(&str))->left(2); // 这样可以,但显得丑陋

首先这个“使用”本身就有问题,只添加一个函数还没什么,但是如果有数据成员你的这个使用方法就不行了,是访问不到数据成员的。

所以这种拓展不可行,一个办法像楼上上说的改string类的代码,第二个就是将要用有left函数的string类的地方改用类A。

附:
你的left函数【【【就是】】】如题目所给的实现的吗?就是截取字符串的前多少个字符?
如果是的话用string类的substr函数就行了:
ipqtjmqj 2017-01-20
  • 打赏
  • 举报
回复
要么直接改源码,要么只能用预处理器了,但比较危险, 见http://ideone.com/dnjbwj

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧