0

我需要的可以通过将this封闭类的指针存储到嵌套类中来完成,例如:

class CEnclosing {
public:
    class CNested : public CSomeGeneric {
    public: 
        CNested(CEnclosing* e) : m_e(e) {}
        virtual void operator=(int i) { m_e->SomeMethod(i); }
        CEnclosing* m_e;
    };

    CNested nested;

    CEnclosing() : nested(this) {}

    virtual void SomeMethod(int i);
};


int main() 
{
    CEnclosing e;
    e.nested = 123;
    return 0;
}

这很好用,但sizeof(void*)每个嵌套成员类需要更多的内存字节。是否存在有效且可移植的方法来执行此操作,而无需存储指向 in 实例的CEnclosing指针m_e

4

4 回答 4

2

我相信以下内容可以移植;虽然它不是万无一失的。具体来说,它不适用于虚拟继承。

另外,我想指出它是不安全的,因为即使您传递的成员与您计算偏移量的成员不对应,它也会愉快地编译:

#include <iostream>

template <typename C, typename T>
std::ptrdiff_t offsetof_impl(T C::* ptr) {
    C c; // only works for default constructible classes
    T* t = &(c.*ptr);
    return reinterpret_cast<char*>(&c) - reinterpret_cast<char*>(t);
}

template <typename C, typename T, T C::* Ptr>
std::ptrdiff_t offsetof() {
    static std::ptrdiff_t const Offset = offsetof_impl(Ptr);
    return Offset;
}

template <typename C, typename T, T C::* Ptr>
C& get_enclosing(T& t) {
    return *reinterpret_cast<C*>(reinterpret_cast<char*>(&t)
         + offsetof<C, T, Ptr>());
}

// Demo
struct E { int i; int j; };

int main() {
    E e = { 3, 4 };

    //
    // BEWARE: get_enclosing<E, int, &E::j>(e.i); compiles ERRONEOUSLY too.
    //                                   ^ != ^
    //
    E& ref = get_enclosing<E, int, &E::j>(e.j);

    std::cout << (void const*)&e << " " << (void const*)&ref << "\n";
    return 0;
}

尽管如此,它确实在这个简单的示例上运行,这让我在我的初始实现中(已经)找到了2 个错误。小心处理

于 2014-02-01T15:07:50.907 回答
2

如前所述,C++ 没有提供任何方法来做到这一点。嵌套类没有特殊的方法可以找到它的封闭类。您已经拥有的解决方案是推荐的方法。

如果您有一个高级场景,并且如果您准备维护不可移植的代码,并且如果存储额外指针的成本足够重要以使用有风险的解决方案,那么有一种基于 C++ 对象模型的方法。有一些我不会涉及的附带条件,您可以依赖以可预测的顺序在内存中布置的封闭类和嵌套类,并且在封闭类和嵌套类的开始之间存在固定的偏移量。

代码类似于:

   CEnclosing e;
   int offset = (char*)&e.nested - (char*)&e;
   //... inside nested class
   CEnclosing* pencl = (CEnclosing*)((char*)this - offset);

OTOH 同样有可能 offsetof 宏可能只是为你做,但我还没有尝试过。

如果您真的想这样做,请阅读标准中的可复制和标准布局。

于 2014-02-01T14:29:37.447 回答
1

您的问题的明确而简单的答案是否定的,C++11 没有任何特殊功能来处理您的场景。但是 C++ 中有一个技巧可以让你这样做:

如果 CEnclosure 没有虚函数,则指向的指针nested将与指向包含实例的指针具有相同的值。那是:

(void*)&e == (void*)&e.nested

这是因为变量nested是 CEnclosure 类中的第一个。

但是,由于您在 CEnclosure 类中有一个虚函数,那么您需要做的就是从中减去 vtable 大小&e.nested,您应该有一个指向e. 不过,不要忘记正确投射!


编辑:正如斯蒂芬罗兰所说,这是一个危险的解决方案,老实说,我不会使用它,但这是我能想到的从嵌套类访问封闭类的唯一方法(或技巧)。就个人而言,如果我真的想将内存使用优化到您提到的水平,我可能会尝试重新设计这两个类之间的关系。

于 2014-02-01T13:50:45.250 回答
1

如何使用这样的多重继承:

class CNested {
public: 
    virtual void operator=(int i) { SomeMethod(i); }
    virtual void SomeMethod(int i) = 0;
};

class CEnclosing: public CSomeGeneric, public CNested {
    int nEncMember;
public:
    CNested& nested;
    CEnclosing() : nested(*this), nEncMember(456) {}
    virtual void SomeMethod(int i) { std:cout << i + nEncMember; }
};
于 2020-07-15T10:51:49.647 回答