需要调用没有对象的非静态方法
Need to invoke non-static method without object
考虑以下 C++ 代码:
class Foo {
public:
int a;
};
class Bar {
public:
int w = 1;
bool are_foos_equal(Foo* f1, Foo* f2) { return f1->a * w == f2->a * w; }
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
现在,这无法编译,因为在 FooEqual
的 operator ()
中我无法调用非静态 are_foos_equal
.
我的问题是:fooset
是否有可能以某种方式使用 are_foos_equal
?我知道我可以将 are_foos_equal
设为静态,但我给出的示例代码只是为了说明我的问题,不幸的是,这个问题发生在一个更大的项目中,即使这意味着设计有些错误,如果可能的话,我想通过一些技巧来拯救它。
编辑
我在Bar
中添加了一个非静态成员变量w
来强调are_foos_equal
的"non-staticness"。
正确的选择肯定是使 are_foos_equal
静态化。我强烈建议这样做而不是 hack。项目越大,它就需要越干净,这样它才不会陷入无法维护的混乱局面。
但如果这真的不是一个选项,我看到了一些其他的可能性:
在 FooEqual
:
中动态创建一个 Bar
对象
return Bar().are_foos_equal(f1, f2);
为此目的 FooEqual
存储静态 Bar
对象:
bool operator() (Foo* f1, Foo* f2) const {
static Bar bar;
return bar.are_foos_equal(f1, f2);
}
调用未定义的行为,在空指针上调用are_foos_equal
并希望它不会做任何坏事。我强烈反对这个:
return static_cast<Bar*>(nullptr)->are_foos_equal(f1, f2);
您可以在 FooEqual
中维护对父 Bar
对象的引用:
Bar() : fooset{10, FooHash{}, FooEqual{*this}}
{}
struct FooEqual {
Bar& parent;
bool operator () (Foo* f1, Foo* f2) const {
return parent.are_foos_equal(f1, f2);
}
};
由于在 std::unordered_set
中声明构造函数的方式,您需要提供存储桶计数,这有点遗憾。如果您愿意,可以从默认构造的 std::unordered_set
中获取默认值。
将 are_foos_equal()
移到 class 之外,使其成为自由函数。它应该是 Bar
的成员没有意义。示例:
class Foo {
public:
int a;
};
bool are_foos_equal(Foo* f1, Foo* f2)
{return f1->a == f2->a;}
class Bar {
public:
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
这里可能是微不足道的,因为 are_foos_equal
可能是静态的,因为它既不使用也不改变 this
中的任何内容
=> 第一种方式只是声明 are_foos_equal
静态。
或者,如果被调用的函数不能是静态的,因为它使用或更改了它的对象,您将不得不更改 FooEqual
以包含一个 Bar
对象(或指向它的指针或引用) .因为 C++ 不是 java: 内部 classes 没有隐藏的指针指向包含 class.
的对象
=> 第二种方式在 FooEqual
中添加对 Bar
的引用并在构建时设置它:
struct FooEqual {
const Bar &bar;
FooEqual(const Bar& bar): bar(bar) {};
bool operator () (Foo* f1, Foo* f2) const {
return bar.are_foos_equal(f1, f2);
}
考虑以下 C++ 代码:
class Foo {
public:
int a;
};
class Bar {
public:
int w = 1;
bool are_foos_equal(Foo* f1, Foo* f2) { return f1->a * w == f2->a * w; }
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
现在,这无法编译,因为在 FooEqual
的 operator ()
中我无法调用非静态 are_foos_equal
.
我的问题是:fooset
是否有可能以某种方式使用 are_foos_equal
?我知道我可以将 are_foos_equal
设为静态,但我给出的示例代码只是为了说明我的问题,不幸的是,这个问题发生在一个更大的项目中,即使这意味着设计有些错误,如果可能的话,我想通过一些技巧来拯救它。
编辑
我在Bar
中添加了一个非静态成员变量w
来强调are_foos_equal
的"non-staticness"。
正确的选择肯定是使 are_foos_equal
静态化。我强烈建议这样做而不是 hack。项目越大,它就需要越干净,这样它才不会陷入无法维护的混乱局面。
但如果这真的不是一个选项,我看到了一些其他的可能性:
在
中动态创建一个FooEqual
:Bar
对象return Bar().are_foos_equal(f1, f2);
为此目的
FooEqual
存储静态Bar
对象:bool operator() (Foo* f1, Foo* f2) const { static Bar bar; return bar.are_foos_equal(f1, f2); }
调用未定义的行为,在空指针上调用
are_foos_equal
并希望它不会做任何坏事。我强烈反对这个:return static_cast<Bar*>(nullptr)->are_foos_equal(f1, f2);
您可以在 FooEqual
中维护对父 Bar
对象的引用:
Bar() : fooset{10, FooHash{}, FooEqual{*this}}
{}
struct FooEqual {
Bar& parent;
bool operator () (Foo* f1, Foo* f2) const {
return parent.are_foos_equal(f1, f2);
}
};
由于在 std::unordered_set
中声明构造函数的方式,您需要提供存储桶计数,这有点遗憾。如果您愿意,可以从默认构造的 std::unordered_set
中获取默认值。
将 are_foos_equal()
移到 class 之外,使其成为自由函数。它应该是 Bar
的成员没有意义。示例:
class Foo {
public:
int a;
};
bool are_foos_equal(Foo* f1, Foo* f2)
{return f1->a == f2->a;}
class Bar {
public:
struct FooHash { size_t operator () (Foo* f) const { return f->a; } };
struct FooEqual {
bool operator () (Foo* f1, Foo* f2) const {
return are_foos_equal(f1, f2);
}
};
std::unordered_set<Foo*, FooHash, FooEqual> fooset;
};
这里可能是微不足道的,因为 are_foos_equal
可能是静态的,因为它既不使用也不改变 this
=> 第一种方式只是声明 are_foos_equal
静态。
或者,如果被调用的函数不能是静态的,因为它使用或更改了它的对象,您将不得不更改 FooEqual
以包含一个 Bar
对象(或指向它的指针或引用) .因为 C++ 不是 java: 内部 classes 没有隐藏的指针指向包含 class.
=> 第二种方式在 FooEqual
中添加对 Bar
的引用并在构建时设置它:
struct FooEqual {
const Bar &bar;
FooEqual(const Bar& bar): bar(bar) {};
bool operator () (Foo* f1, Foo* f2) const {
return bar.are_foos_equal(f1, f2);
}