将不正确的指针赋值技巧添加到C++的“扩展方法支持”会成为未来的一个_problem问题吗?

问题描述:

我的解决方案我该怎么使用,以“C++扩展方法”添加到JNI jobjects使NDK代码的可读性像(统一函数调用语法)为:将不正确的指针赋值技巧添加到C++的“扩展方法支持”会成为未来的一个_problem问题吗?

  • 子类,我想补充扩展方法的类。
  • 对于调用“扩展方法”,将类型为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; 
} 

你认为这种不正确的指针赋值,因为“扩展方法”只访问扩展类&扩展类的公共成员做不会有任何现场的变量,可以在将来代表一个问题吗? 对象的大小是相同的。

非常感谢。

+1

这只适用于您未将任何数据成员添加到PersonExtensions类的情况。尽管如此,当你说'pE'指向的东西实际上不是你声称的东西时,它仍然是严格的走样。 –

+5

解引用'pE'是未定义的行为,任何关于接下来会发生什么的猜测都是浪费时间。 –

+2

刚刚创建一个函数'personSize(const Person&person){return 5 + person.age(); }'?在任何“人”的情况下,都可以在没有任何UB的情况下合法地调用。 – cmaster

你在你的问题代码中做什么是未定义的行为,所以一个特别优化的编译器可能会对它做很有趣的事情。换句话说,不要这样做,即使它在测试时仍然有效,它可能会在任何时候中断。只有确保实际工作的方法是在每次编译后检查生成的汇编代码,以确保它能够做到你想要的,这实际上是不可能的,所以它从来不是安全的。


您正在使用私有继承。因此,对于同样的效果,你可以只是这样做:

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

如果改为使用公有继承(所以你也可以通过打电话PersonExtensionsPerson方法),那么你需要添加一个getter方法_person(对于需要真实Person的情况)和/或为Person方法(用于所谓的静态多态性)添加委托。

+0

'_person'可以很容易作为参考 – Caleth

+0

@Caleth真,那会更好。随意编辑。或者如果我记得今天晚些时候我会做。 – hyde

+1

是的,执行包装是我做的第一选择,然后我认为这可能是一个性能损失,并将其实现为@cmaster所说的函数调用。但是随着函数的调用没有UFCS,代码的可读性就会降低。然后我寻找更多扭曲的形式。由于性能的成本可以忽略不计,我将回到包装。 –

这是未定义的行为

是的,可以在任何时候打破。

考虑重载->*或其他东西。

或者只是使用免费功能。

如果你真的想缀表示法:

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 

这里我们没有一个扩展方法,但我们有一个扩展方法指针。

+0

谢谢@Yakk我不知道/使用这个覆盖永远不会,必须学习。你的意思是在PersonExtensions中使用它吗?我在最初的问题中没有提到Person类是我的代码的外部。我编辑问题。 –

+1

@JoaquínLuisMonleónIrisarri扩展方法指针的玩具实现添加澄清。 – Yakk