向 C++ 添加“扩展方法支持”的错误指针分配技巧将来会成为问题吗?
Can incorrect pointer assignment trick for add “Extension methods support” to C++ be a _problem in future?
我将用于向 JNI jobjects 添加“C++ 扩展方法”以使 NDK 代码更具可读性(如(统一函数调用语法))的解决方案是:
- Subclass class 我要添加扩展方法。
- 为了调用“扩展方法”,使 ExtensionsClass 类型的指针指向 OriginalClass -(尽管指向的对象不是 ExtensionsClass)。
重载最小,我们可以访问原始 class 的 public 方法。
#include <iostream>
// Represents a class external to my source
class Person {
public:
Person(){
privateage = 20;
}
int age() { return privateage; }
private:
int privateage;
short anotherField;
};
class PersonExtensions : private Person {
public:
inline int size() { return 5 + age(); }
//NoFieldsOnExtensionClass
};
int main() {
Person person;
PersonExtensions* pE = (PersonExtensions*) &person;
std::cout << pE -> size() << std::endl;
std::cout << (*pE).size() << std::endl;
std::cout << sizeof(Person) << std::endl;
std::cout << sizeof(PersonExtensions) << std::endl;
return 0;
}
你认为这个指针赋值不正确吗,因为“扩展方法”只访问了扩展 class 的 public 成员和扩展 class 不会有任何字段变量, 能代表未来的问题吗?
对象大小相同
非常感谢。
这是未定义的行为。
是的,随时都可能崩溃。
考虑重载 ->*
或其他方法。
或者只是使用免费功能。
如果你真的想要中缀表示法:
template<class T, class F>
struct extension_method_t {
F f;
friend auto operator->*( T& t, extension_method_t const& self ) {
return [&t,&self](auto&&...args)->decltype(auto) {
return self.f( t, decltype(args)(args)... );
};
}
};
template< class T, class F >
extension_method_t<T,F> extension_method( F f ) {
return {std::move(f)};
}
然后:
auto size = extension_method<Person>([](auto& person)->int{
return 5+person.age();
});
Person p;
std::cout << (p->*size)() << "\n"; // prints p.age()+5
这里我们没有扩展方法,但是我们有一个扩展方法指针。
你在你的问题代码中所做的是未定义的行为,所以一个特别优化的编译器可能会用它做真正的"fun"事情。换句话说,不要这样做,即使您测试它可以工作,它也可能随时崩溃。确保它实际工作的唯一方法是在每次编译后检查生成的汇编代码,以确保它做你想做的,这基本上是不可能的,所以它永远不安全。
您正在使用私有继承。所以为了同样的效果,你可以这样做:
class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
如果您改为使用 public 继承(这样您就可以通过 PersonExtensions
调用 Person
方法),那么您需要为 _person
(对于需要真实 Person
的情况),and/or 为 Person
方法添加委托(对于所谓的静态多态性)。
我将用于向 JNI jobjects 添加“C++ 扩展方法”以使 NDK 代码更具可读性(如(统一函数调用语法))的解决方案是:
- Subclass class 我要添加扩展方法。
- 为了调用“扩展方法”,使 ExtensionsClass 类型的指针指向 OriginalClass -(尽管指向的对象不是 ExtensionsClass)。
重载最小,我们可以访问原始 class 的 public 方法。
#include <iostream>
// Represents a class external to my source
class Person {
public:
Person(){
privateage = 20;
}
int age() { return privateage; }
private:
int privateage;
short anotherField;
};
class PersonExtensions : private Person {
public:
inline int size() { return 5 + age(); }
//NoFieldsOnExtensionClass
};
int main() {
Person person;
PersonExtensions* pE = (PersonExtensions*) &person;
std::cout << pE -> size() << std::endl;
std::cout << (*pE).size() << std::endl;
std::cout << sizeof(Person) << std::endl;
std::cout << sizeof(PersonExtensions) << std::endl;
return 0;
}
你认为这个指针赋值不正确吗,因为“扩展方法”只访问了扩展 class 的 public 成员和扩展 class 不会有任何字段变量, 能代表未来的问题吗? 对象大小相同
非常感谢。
这是未定义的行为。
是的,随时都可能崩溃。
考虑重载 ->*
或其他方法。
或者只是使用免费功能。
如果你真的想要中缀表示法:
template<class T, class F>
struct extension_method_t {
F f;
friend auto operator->*( T& t, extension_method_t const& self ) {
return [&t,&self](auto&&...args)->decltype(auto) {
return self.f( t, decltype(args)(args)... );
};
}
};
template< class T, class F >
extension_method_t<T,F> extension_method( F f ) {
return {std::move(f)};
}
然后:
auto size = extension_method<Person>([](auto& person)->int{
return 5+person.age();
});
Person p;
std::cout << (p->*size)() << "\n"; // prints p.age()+5
这里我们没有扩展方法,但是我们有一个扩展方法指针。
你在你的问题代码中所做的是未定义的行为,所以一个特别优化的编译器可能会用它做真正的"fun"事情。换句话说,不要这样做,即使您测试它可以工作,它也可能随时崩溃。确保它实际工作的唯一方法是在每次编译后检查生成的汇编代码,以确保它做你想做的,这基本上是不可能的,所以它永远不安全。
您正在使用私有继承。所以为了同样的效果,你可以这样做:
class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
如果您改为使用 public 继承(这样您就可以通过 PersonExtensions
调用 Person
方法),那么您需要为 _person
(对于需要真实 Person
的情况),and/or 为 Person
方法添加委托(对于所谓的静态多态性)。