问题描述
与其他语言相反,定义后不能扩展C ++类。 这就是为什么自由函数优于成员函数的原因,因为自由函数是扩展类行为的更通用的方法。
同时,点语法(仅用于成员函数)可以具有一些符号上的优势,例如,当某个对象比函数调用中的其他参数“重要”时。
例如,
allocator a;
a.allocate(n); // vs. allocate(a,n);
这在语言上产生了张力。 (在早期的C ++中,这种紧张导致了the肿类的创建。)
在最佳情况下,区别在于语法。 在最坏的情况下,使用点的期望语法会强制在类内部定义方法(存在通过包含大量成员函数而使类变大的风险)。
到目前为止,这就是C ++,我们习惯于此。
但是,在某些情况下有一个漏洞。 问题是这个漏洞是否经常被利用,或者是否会在以后造成问题。
事实是,可以通过打开模板成员函数来模拟类的扩展。
例如:
struct A{
void f(int n) const{...}
void g(std::string s) const{...};
};
“成员” g
无法扩展以使这项工作A a; a.g(42)
。
但是,可以这样做使语法起作用:
struct A{
void f(int n) const{}
template<class T> void g(T t) const; // this can be even customized by a user of the library
};
// this can be defined anywhere down the road (but before `A::g<T>` is instantiated I think).
template<> void A::g<int>(int t) const{}
template<> void A::g<std::string>(std::string t) const{}
该扩展名不是通用的,在这种情况下,任何扩展名都必须具有固定的名称(和一个参数),但仍然感觉像是一个扩展名。
除了丑陋的类模板代码外,使用这种技术扩展类还有什么问题吗?
在一般情况下这并不简单,但是甚至可以扩展该技术以定制我认为的不同返回类型(在这里我使用void
为简单起见,另一种简单情况是当返回类型为{{1} }本身。)
我可以看到的一个问题是部分专业化可能非常困难。 另一个问题是,实例化的顺序可能会出现问题,需要在首次使用(?)之前定义自定义项。
自定义命名函数并不是很令人印象深刻。
但是可以自定义其他功能,例如T
。实际上,这就像是从类外部进行重载,这是正常方式无法实现的。
解决方法
除了丑陋的类模板代码外,使用这种技术扩展类还有什么问题吗?
不,它被称为“成员模板”,在C ++中是完全有效的东西。
更新:
我知道这是有效的。我想知道这是否是经常使用的技术。
我个人从来没有经常使用它。通常,一直在决定将整个类实现为模板,而不是专注于单个功能。但同时,我相信这类事情取决于您要达到的目标以及您的个人品味。我的意思是它是语言的功能,所以为什么在感觉合适时不使用它。