Мое решение, которое я собираюсь использовать, чтобы добавить «Методы расширения C ++» к JNI-объектам, чтобы сделать код NDK более читабельным, как (Uniform Function Call Syntax):
Перегрузка минимальна & мы можем получить доступ к открытым методам класса Original.
#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 PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};
Если вы вместо этого использовали публичное наследование (так что вы могли бы просто позвонить Person
методы через PersonExtensions
), тогда вам нужно добавить геттер для _person
(для случаев, когда реальный Person
и / или добавить делегатов для Person
методы (для так называемого статического полиморфизма).
Это неопределенное поведение.
Да, это может сломаться в любой момент.
Рассмотрим перегрузку ->*
или что-то вместо этого.
Или просто с помощью бесплатной функции.
Если вы действительно хотите инфиксную запись:
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
здесь у нас нет метода расширения, но у нас есть указатель на метод расширения.