2017-02-12 4 views
1

Я просто столкнулся с фрагментом кода, который мне кажется довольно странным (см. Ниже в качестве минимального примера), derived::base является ссылкой на другой объект типа base, может кто-нибудь мне помочь ответить на вопросы в комментариях?базовый класс является ссылкой на другой объект

class base{ 
public: 
    int a; 
    int b; 
}; 

class derived : public base{ 
public: 
    double c; 
    void run(const base & bs){ 
    ((base &) *this) = bs; // what does this line do? 
          // Is derived::base now a copy of bs? 
          // If yes, but why not write ((base) *this) = bs? 
          // if not, then derived::base is a reference to bs, 
          // then does it mean the memory of derived::base 
          // and members of derived are no longer contiguous? 
    std::cout << "a = " << a << std::endl; 

    } 
}; 

PS

комментарии @LightnessRacesinOrbit помогли многое прояснить вопросы, но я могу только принимать почту ответ, лучше всего по @WhiZTiM

+1

Все это делает вызов конструктора копирования базового класса, который скопирует элементы базового класса (то есть 'a' и' b'), не касаясь ничего в производной части объекта (т. Е. 'C'). Я не понимаю, почему память больше не будет соприкасающейся. – imreal

+0

afaik у вас никогда не было гарантии, что члены объектов хранятся в непрерывной памяти, даже без этого «копирования только базовых членов класса». Возможно, есть какое-то недоразумение в отношении значения «смежных». Можете ли вы объяснить немного больше, что именно вас беспокоит по поводу этого кода? – user463035818

+0

@imreal, но почему бы не написать '((base) * this) = bs' при вызове конструктора копирования? – Allanqunzi

ответ

2
void run(const base & bs){ 
    ((base &) *this) = bs; 
    std::cout << "a = " << a << std::endl; 
} 

Приведенные выше код может быть разбит как:

void run(const base & bs){ 
    base& base_of_this_instance = *this; 
    base_of_this_instance = bs; 
    std::cout << "a = " << a << std::endl; 
} 

память для объекта derived может быть изложена как:

|| int a |x| int b |y| int c || // <- x and y represents some hypothetical padding 
||  base   |y|   || // <- We can slice `derived` and retrieve only base 
||   derived    || // <- Memory consumed by derived 

В вашем методе derived::run, во-первых, ссылка на base части derived получают, во-вторых, что base присваивается bs. Это присвоение вызовет оператор присваивания копий base. Это означает, что теперь базовая часть теперь будет содержать копию того, что было в bs.

+0

Какие отличия делают if, если они написаны как '((base) * this) = bs'? – Allanqunzi

+0

@Allanqunzi: Вместо этого вы получаете бесполезную временную копию. –

+0

'((base) * this) = bs' будет просто иметь' bs', назначенный нарезанной части 'base' из производного. Поскольку эта часть * нарезанной * является временным неназванным объектом, она будет уничтожена в конце ';'. Фактически вы теряете работу. 'производный' не будет затронут – WhiZTiM

0

Результат

((base &) *this) 

ссылки на базовый класс

Вы можете сохранить его в переменной:

base& refToBase = ((base &) *this); 

refToBase является ссылкой на тот же объект, который этот

После этого у вас есть присваивание

refToBase = bs; 

Это присвоит значение Bs, чтобы refToBase объект

int i = 10; 
int p = 20; 
int& refI = i; 
int& refP = p; 
refI = refP; // i == 20 
p = 15; // p ==15 but i == 20 

Так после того, как «странный код» из вашего примера выполняются мы имеем копии bs.a и bs.b в производном :: а и производным :: б

память о производном :: Базовые и производные :: гр еще одна партии

+0

Почему бы просто не написать '((base) * this) = bs' или' deriv :: base = bs'? – Allanqunzi

+0

@Allanqunzi: Потому что первая создает временную копию, а вторая - фэнтези. –

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