从具有公共基(C++)的函数对象进行乘法继承
Multiply inheriting from function objects with a common base (C++)
我有一些函数对象没有成员变量。函数对象本质上非常简单。它们都继承自unary_function<>
或binary_function<>
。例如,一对函数对象可能是这样的:
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
int operator() (int a, int b) const { /* do something */ }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>, public key_to_hash_method
{
int operator() (int a, int b) const { /* do something while utilizing key_to_hash_method */ }
};
/* and more variations of these function objects */
模板类通过将这些函数对象作为策略的模板参数来使用它们。然后模板类从它们继承:
template <typename hash_method>
class foo : public hash_method
{
public:
/* do something while using hash_method as well as using the information provided by binary_function<> to selective compile different functions*/
};
当然,为了使示例保持简单,就有用性而言,以上内容可能没有多大意义。
为什么我要继承而不是使用组合?只是为了避免空的类占用空间。节省的空间是否微不足道并不是问题的关键。
从上面的代码中可以看出,binary_function<int, int, int>
将被继承两次,这会产生警告(在VC++2008中):
Warning 1 warning C4584: 'hash_shrink_method_1<key_to_hash_method>' : base-class 'std::binary_function<_Arg1,_Arg2,_Result>' is already a base-class of 'key_to_hash_method_1' c:visual studio 2008projectsdefaulttemplateargumentsmain.cpp 12
现在一般来说,在多重继承中,这是通过虚拟继承来解决的;在这种情况下,我想避免这种情况。在这种情况下,我能做些什么来删除警告?
我的直接解决方案是不从binary_function<>
继承,因为我假设key_to_hash_method
将是binary_function
。这个解决方案感觉有点像一个程序员,他无权包含guards或pragma once
语句。是的,他可以避免两次包含头,但他宁愿编译器帮他解决。在这种情况下,我也希望如此。
示例代码,如果您想尝试一下:
#include <functional>
using namespace std;
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
int operator() (int a, int b) const { return a + b; }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>, public key_to_hash_method
{
int operator() (int a, int b) const { return key_to_hash_method::operator()(1, 2) * 5; }
};
template <typename hash_method>
class foo : public hash_method
{
public:
int test()
{
/* in actual code, this function selectively calls other functions
depending on whether hash_method is unary or binary */
return hash_method::operator()(5, 6);
}
};
int main()
{
foo<hash_shrink_method_1<key_to_hash_method_1> > f;
printf("%in", f.test());
}
您的hash_shrink_method_1
不需要直接从binary_function
继承,因为您假设其参数类key_to_hash_method
已经继承了。如果您想确定,可以添加一个静态断言(std::is_base_of
);不过,如果您已经有了C++11,那么无论如何都可以去掉过时的binary_function
。
语言律师部分
GCC给出了更好的警告:
mi.C: In instantiation of ‘hash_shrink_method_1<key_to_hash_method_1>’:
mi.C:18: instantiated from ‘foo<hash_shrink_method_1<key_to_hash_method_1> >’
mi.C:30: instantiated from here
mi.C:12: warning: direct base ‘std::binary_function<int, int, int>’ inaccessible in ‘hash_shrink_method_1<key_to_hash_method_1>’ due to ambiguity
也就是说,如果直接和间接从同一个基类继承,则无法访问直接基类。尝试这样做将是一个编译时错误。
hash_shrink_method_1<key_to_hash_method_1> foo;
binary_function<int, int, int>& bar = foo; // error: ambiguous
这是无法消除歧义的。
除了使用虚拟继承之外,显而易见的解决方案是引入继承的中间层。
template <typename T>
struct wrapped : public T {};
然后
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public wrapped < binary_function<int, int, int> >,
public wrapped <key_to_hash_method >
现在可以消除歧义:
hash_shrink_method_1<key_to_hash_method_1> foo;
foo::wrapped<binary_function<int, int, int> >& intermediate = foo;
binary_function<int, int, int>& bar = intermediate;
OOP/OOD律师部分
但是请注意,您的类现在有两个operator()(int,int)
函数可公开访问。将选择哪一个取决于您如何访问它们。
foo<hash_shrink_method_1<key_to_hash_method_1> > f;
hash_shrink_method_1<key_to_hash_method_1>& ff = f;
cout << ff(5,6) << endl; // 15
key_to_hash_method_1& gg = ff;
cout << gg(5,6) << endl; // 11
如果这不是您想要的,那么您不应该在这里使用公共继承,也不应该在一般情况下使用继承。这里没有继承的理由。
我看到了两种非常好的方法。
你已经提到的第一个:作文。这很简单,代码看起来也很自然。
然而,从示例的运行方式来看,代码甚至不需要实例化任何这些函数对象。因此,您可以更改类,使其具有与operator()
相同的静态方法,例如
struct key_to_hash_method_1 : public binary_function<int, int, int>
{
static int invoke (int a, int b) { return a + b; }
int operator() (int a, int b) const { return a + b; }
};
template <typename key_to_hash_method>
struct hash_shrink_method_1 : public binary_function<int, int, int>
{
static int invoke (int a, int b) { return key_to_hash_method::invoke(1, 2) * 5 }
int operator() (int a, int b) const { return key_to_hash_method::invoke(1, 2) * 5; }
};
请注意,hash_shrink_method_1
不再需要从key_to_hash_method_1
继承。类似地,foo
不需要从hash_method
继承。
(使用这些静态方法的另一种选择是实现单例模式)
我想到了最后一个想法:由于您使用模板来调用方法,所以实际上不需要使用binary_function
(至少就这些示例而言)。如果您的实际情况与示例代码相似,那么可能需要去掉binary_function
。
- 如何创建对象函数指针C++映射?
- 为什么我可以改变常量对象中的成员变量,这是返回常量对象函数的结果?
- 如何将对象函数的实例传递给另一个函数
- 调用模板函数的问题"No matching function for call"参数:迭代器、对象函数
- makefile对我的名称空间对象/函数/构造函数的不确定引用
- 将对象函数转换为函数指针
- 非对象函数/类函数C++
- 线程对象函数 C++
- C 将成员对象函数分配给类成员功能
- 使用基本指针调用派生对象函数
- 可以(通过编译器)使用多少个线程来初始化全局对象(函数main之前)
- C++类对象函数
- 对对象::函数的未定义引用
- 无法弄清楚将多个对象函数作为单独的线程调用的语法
- 在提升作用域出口中调用对象函数
- 使用基指针来使用派生对象函数
- 在for_each lambda 中调用对象函数
- C++:: 模板函数 - 从对象函数获取对象的地址
- Qt5 未解析的外部静态元对象函数
- 通过变量使用对象和对象函数