2014-01-28 4 views
6

Я хотел бы составлять указатели элементов. В основном у меня есть основной класс с другим членом. Как создать указатель-член для основного класса, который указывает на член члена этого класса. Я надеюсь, что ниже код объясняет то, что я пытаюсь сделать:Могу ли я составить указатели на член

struct SubUnit 
    { 
    int value; 
    }; 
    struct Unit 
    { 
    SubUnit sub_unit; 
    }; 

    void Test() 
    { 
    SubUnit Unit::* ptr1 = &Unit::sub_unit; // WORKING 
    int Unit::* ptr2 = &Unit::sub_unit::value; // NOT WORKING ! 
    } 
+0

':: value' является' int' но вы присваиваете его к указателю на член? – 0x499602D2

+0

Вам нужно создать объект Unit, чтобы иметь что-то, что можно было бы указывать на .... ok, nevermind. –

+0

@JohnnyMopp Не обязательно. – 0x499602D2

ответ

3

Использование подклассу путает здесь, так как в целом подклассе используется для наследования, так что давайте говорить о данных член: sub_unit является членом данных Unit.

И то, что вы просите за это не представляется возможным, Unit::* может представлять только смещение в любом Unit сам или один из его базовых классов:

struct SubUnit { int value; }; 

struct Unit: SubUnit {}; 

int main() { int Unit::* p = &Unit::value; } 
+0

Извините, если вопрос непонятен, но в в моем случае я бы предпочел использовать композицию над наследством. – Arthur

+2

@jules: вопрос совершенно ясен, и так ответ: * невозможно * (и, кстати, вы правы, предпочитая композицию над наследованием). –

+0

Еще лучше, назовем это * (данными) членом *, так как это стандартная терминология. –

2

Это, кажется, как дубликат этого вопроса:
Nested data member pointer - not possible?

суть принятого ответ говорит:

пуанты г-на-член может быть сформирован только выражением типа & qualified_id, который не ваш случай

C++ стандарт говорит, что в пункте 8.3.3:
Указатель членов:

В объявлении TD, где D имеет вид

nested-name-specifier * attribute-specifier-seqopt cv-qualifier-seqopt D1 

, а спецификатор вложенных имен обозначает класс, а тип идентификатора в объявлении T D1 - это «имя-тип-тип-тип T-типа», тогда тип идентификатора D является «производным-декларатором» -type-list cv qualifier-seq указатель на член класса insested-name-specifier типа T ". Необязательный атрибут-спецификатор-seq (7.6.1) относится к указателю-к-члену.

Оказывается, есть способ сделать то, что вы хотите, что, похоже, работает над моим текущим компилятором (apple llvm 5.0). Тем не менее, очень зависит от реализации, и я определенно рекомендую не использовать это решение в любом виде кода производства:

//added a few data members to make it non-trivial 
struct SubUnit { 
    double d; 
    int value; 
}; 
struct Unit { 
    bool b; 
    char c; 
    SubUnit sub_unit; 
}; 

intptr_t suOffset = offsetof(Unit, sub_unit); 
intptr_t intOffset = offsetof(SubUnit, value); 
intptr_t totalOffset = suOffset + intOffset; 

// there is no way to convert this offset directly in a 
// pointer-to-member AFAIK, so we have to trick a bit 
int Unit::* pui = nullptr; 
auto puiAddr = &pui; 
intptr_t* puiAddrAsIntPtrPtr = reinterpret_cast<intptr_t*>(puiAddr); 
*puiAddrAsIntPtrPtr = totalOffset; 

//pui should now "point to the right offset" 
//let's test it 
Unit u; 
u.sub_unit.value = 123456; 

int val = u .* pui; 
std::cout << "val: " << val << std::endl; 
+0

Я бы скорее согласился с тем фактом, что это невозможно – Arthur

+0

Ну, это, вероятно, правильная вещь ... За исключением того, что технически, в некоторых случаях это действительно возможно;) –

4

Кажется, вы должны сделать это в два этапа:

SubUnit Unit::*pSub = &Unit::sub_unit; 
int SubUnit::*pValue = &SubUnit::value; 

Unit u; 
int theVal = (u.*pSub).*pValue; 
+1

+1 no нужно подозревать иначе, [поскольку вы правы.] (http://ideone.com/ZNQvsJ) Я честно считаю, что это заслуживает лучшего взгляда от OP. – WhozCraig

+0

@WhozCraig Спасибо за то, что вы сделали всю тяжелую работу :-). Я удалю неопределенность из своего ответа. – selalerer

+0

Нет, спасибо * вы *. Я никогда не встречал случая сделать это с * членами данных *, поскольку единственная необходимость, которую я когда-либо имел, была для функций члена * *. Это было образовательное. – WhozCraig

0

обходной может быть построена с лямбда:

struct SubUnit 
    { 
     int value; 
    }; 
    struct Unit 
    { 
     SubUnit sub_unit; 
    }; 

    void Test() 
    { 
     auto composed_mem_ptr = [](Unit & unit) -> int&{ return unit.sub_unit.value; }; 
     Unit unit0{}; 
     composed_mem_ptr(unit0) = 7; 
    } 

 Смежные вопросы

  • Нет связанных вопросов^_^