Всегда ли передача по ссылке позволяет избежать проблемы нарезки? - PullRequest
7 голосов
/ 26 ноября 2011

Это меня немного удивило, но я поигрался с некоторым кодом и обнаружил, что, по крайней мере, на моем компьютере, когда функция принимает родительский класс по ссылке, а вы передаете дочерний экземпляр, проблема срезания не возникает.не происходитДля иллюстрации:

#include <iostream>

class Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Parent::DoSomething" << endl;
    }
};

class Child : public Parent
{
public:
    virtual void doSomething()
    {
        using namespace std;
        cout << "Child::DoSomething" << endl;
    }
};

void performSomething(Parent& parent)
{
    parent.doSomething();
}

int main(int argc, char** argv)
{
    Child myChild;

    performSomething(myChild);

    return 0;
}

Это распечатывает Child::DoSomething.

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

Я просто хочу убедиться, это должно произойти, или это один из тех экземпляров, которые «работают на моей машине»?

Ответы [ 4 ]

11 голосов
/ 26 ноября 2011

«Нарезка» относится к неспособности конструктора базовой копии отличить точные совпадения типов от производных классов. Единственный способ вызвать нарезку - это вызвать конструктор базовой копии. Обычно это происходит при передаче аргументов по значению, хотя могут быть придуманы и другие ситуации:

class Base { };
class Derived : public Base { };

void foo(Base);

int main()
{
  Derived x;

  Base y = x;   // flagrant slicing
  foo(x);       // slicing by passing by value
}

Вы никогда не делаете ничего подобного, поэтому вы не сталкиваетесь с ситуациями нарезки.

9 голосов
/ 26 ноября 2011

Вы видите правильное поведение.Вот как это должно работать.Ссылки работают как указатели.

3 голосов
/ 26 ноября 2011

Это должно произойти.Передача по ссылке ТОЧНО похожа на передачу указателей - под капотом происходит то же самое.В этом нет магии;С каждым экземпляром полиморфного объекта связана таблица виртуальных функций.Пока вы ничего не копируете, вы не потеряете эту информацию, и ваши вызовы виртуальных функций будут работать так, как вы ожидаете.

Причина, по которой вы сталкиваетесь с проблемами при передаче по значениюв том, что он будет использовать конструктор копирования того типа, который вы указали в сигнатуре функции, так что вы получите совершенно новый экземпляр суперкласса.

2 голосов
/ 26 ноября 2011

Да, привязка к ссылке включает динамическое связывание. Это вызвано различием динамического типа объекта и его статического типа.

Если вы берете свой параметр по значению, он становится Parent классом. Хотя если вы передадите что-то через ссылку или указатель и вызовете виртуальную функцию, во время выполнения будет выполняться поиск dynamic type или most-derived type фактического объекта, на который ссылается.

...