Может ли неправильный метод назначения указателей для добавления «Поддержка методов расширения» в C ++ быть _проблемой в будущем?

Мое решение, которое я собираюсь использовать, чтобы добавить «Методы расширения C ++» к JNI-объектам, чтобы сделать код NDK более читабельным, как (Uniform Function Call Syntax):

  • Подкласс класса, который я хочу добавить методы расширения.
  • Чтобы вызвать «Методы расширения», создайте указатель типа ExtensionsClass, чтобы он указывал на OriginalClass — (хотя указанный объект не является ExtensionsClass).

Перегрузка минимальна & мы можем получить доступ к открытым методам класса 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;
}

Считаете ли вы, что это неправильное назначение указателя, поскольку «Метод расширения» доступен только для открытых членов расширенного класса & класс расширения не будет иметь никаких переменных поля, может представлять проблему в будущем?
Размер объекта одинаков.

Большое спасибо.

0

Решение

Что вы делаете в своем коде вопроса Неопределенное поведение, так что особенно оптимизирующий компилятор может делать с ним действительно «забавные» вещи. Другими словами, не делайте этого, он может сломаться в любое время, даже если он работает, когда вы его тестируете. Единственный способ убедиться, что он действительно будет работать, — это проверять созданный ассемблерный код после каждой компиляции, чтобы убедиться, что он выполняет то, что вам нужно, и это практически невозможно, поэтому это никогда не безопасно.


Вы используете частное наследство. Так что для того же эффекта вы можете просто сделать это:

class PersonExtensions {
public:
PersonExtensions(Person *person) : _person(person) {}
inline int size() { return 5 + _person->age(); }
private:
Person *_person;
};

Если вы вместо этого использовали публичное наследование (так что вы могли бы просто позвонить Person методы через PersonExtensions), тогда вам нужно добавить геттер для _person (для случаев, когда реальный Person и / или добавить делегатов для Person методы (для так называемого статического полиморфизма).

1

Другие решения

Это неопределенное поведение.

Да, это может сломаться в любой момент.

Рассмотрим перегрузку ->* или что-то вместо этого.

Или просто с помощью бесплатной функции.

Если вы действительно хотите инфиксную запись:

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

здесь у нас нет метода расширения, но у нас есть указатель на метод расширения.

6

По вопросам рекламы [email protected]