Как вызвать оператор класса вывода ()? [Дубликат]

Наряду с попыткой всего, что предлагает Teo Chuen Wei Bryan, убедитесь, что вы также ссылаетесь на правильное имя Server / Instance в строке подключения.

Если вы используете краткую форму имени хоста / экземпляра на сервере базы данных или в файле web.config, убедитесь, что вы используете полное доменное имя (FQDN) / экземпляр

Кроме того, чтобы проверить подключение с сервера, на котором нет клиента SQL-сервера,

-> создать текстовый файл и изменить его расширение файла на .udl

-> Щелкните правой кнопкой мыши файл, и вы увидите вкладку подключения.

-> Введите имя сервера и зарегистрируйте информацию для проверки соединения с сервером базы данных.

Надеюсь, это поможет.

610
задан Taryn 22 March 2017 в 17:09
поделиться

17 ответов

Хорошо, я попробую после чтения многих сообщений, объясняющих разбиение объектов, но не так, как это становится проблематичным.

Порочный сценарий, который может привести к повреждению памяти, следующий:

  • Класс предоставляет (случайно, возможно, сгенерированное компилятором) назначение в полиморфном базовом классе.
  • Клиент копирует и нарезает экземпляр производного класса.
  • Клиент вызывает функцию виртуального члена, которая обращается к состоянию среза.
2
ответ дан Dude 19 August 2018 в 16:45
поделиться

«Slicing» - это то, где вы назначаете объект производного класса экземпляру базового класса, тем самым теряя часть информации - часть его «нарезана».

Например,

class A {
   int foo;
};

class B : public A {
   int bar;
};

Таким образом, объект типа B имеет два элемента данных: foo и bar.

Тогда, если вы должны были написать это:

B b;

A a = b;

Затем информация в b о члене bar теряется в a.

517
ответ дан ForceBru 19 August 2018 в 16:45
поделиться
  • 1
    Очень информативно, но см. stackoverflow.com/questions/274626#274636 для примера того, как разреза происходит во время вызовов метода (что подчеркивает опасность немного лучше, чем пример простого назначения). – Blair Conrad 8 November 2008 в 14:53
  • 2
    Интересно. Я программировал на C ++ в течение 15 лет, и эта проблема мне никогда не приходила в голову, поскольку я всегда передавал объекты по ссылке как вопрос эффективности и личного стиля. Идет, чтобы показать, как хорошие привычки могут вам помочь. – Karl Bielefeldt 2 February 2011 в 04:48
  • 3
    @Felix Спасибо, но я не думаю, что отбрасывание назад (так как не арифметика указателя) будет работать, A a = b; a теперь является объектом типа A, который имеет копию B::foo. Будет ошибкой вернуть его сейчас, я думаю. – user 12 August 2011 в 13:27
  • 4
    Это не «разрезание», или, по крайней мере, его доброкачественный вариант. Реальная проблема возникает, если вы выполняете B b1; B b2; A& b2_ref = b2; b2 = b1. Вы могли бы подумать, что скопировали b1 в b2, но вы этого не сделали! Вы скопировали часть из b1 в b2 (часть b1, которая B унаследована от A), и оставила остальные части b2 без изменений. b2 теперь является франкенштейновским существом, состоящим из нескольких бит b1, за которым следуют некоторые фрагменты b2. Тьфу! Downvoting, потому что я думаю, что ответ очень промахивается. – fgp 22 January 2013 в 16:07
  • 5
    @fgp Ваш комментарий должен быть прочитан B b1; B b2; A& b2_ref = b2; b2_ref = b1 & quot; Реальная проблема возникает, если вы & quot; ... вытекает из класса с не виртуальным оператором присваивания. Действительно ли A предназначен для деривации? Он не имеет виртуальных функций. Если вы проистекаете из типа, вам приходится иметь дело с тем, что его функции-члены могут быть вызваны! – curiousguy 29 June 2013 в 15:54

Все это хорошие ответы. Я хотел бы добавить пример выполнения при передаче объектов по значению vs по ссылке:

#include <iostream>

using namespace std;

// Base class
class A {
public:
    A() {}
    A(const A& a) {
        cout << "'A' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am an 'A'" << endl; }
};

// Derived class
class B: public A {
public:
    B():A() {}
    B(const B& a):A(a) {
        cout << "'B' copy constructor" << endl;
    }
    virtual void run() const { cout << "I am a 'B'" << endl; }
};

void g(const A & a) {
    a.run();
}

void h(const A a) {
    a.run();
}

int main() {
    cout << "Call by reference" << endl;
    g(B());
    cout << endl << "Call by copy" << endl;
    h(B());
}

Выход:

Call by reference
I am a 'B'

Call by copy
'A' copy constructor
I am an 'A'
28
ответ дан geh 19 August 2018 в 16:45
поделиться
  • 1
    Это самое простое решение, позволяющее избежать наложения объектов, +1. – mucaho 3 November 2015 в 14:03
  • 2
    Отличный пример: +1. – Jarvis 7 February 2017 в 16:18
  • 3
    Здравствуйте. Отличный ответ, но у меня есть один вопрос. Если я сделаю что-то вроде этого ** dev d; base * b = & amp; d; ** Нарезка также имеет место? – John 10 July 2018 в 06:58

Когда объекту класса Derived присвоен объект Base class Object, все члены объекта производного класса копируются в объект базового класса, за исключением членов, которых нет в базовом классе. Эти члены удаляются компилятором. Это называется Object Slicing.

Вот пример:

#include<bits/stdc++.h>
using namespace std;
class Base
{
    public:
        int a;
        int b;
        int c;
        Base()
        {
            a=10;
            b=20;
            c=30;
        }
};
class Derived : public Base
{
    public:
        int d;
        int e;
        Derived()
        {
            d=40;
            e=50;
        }
};
int main()
{
    Derived d;
    cout<<d.a<<"\n";
    cout<<d.b<<"\n";
    cout<<d.c<<"\n";
    cout<<d.d<<"\n";
    cout<<d.e<<"\n";


    Base b = d;
    cout<<b.a<<"\n";
    cout<<b.b<<"\n";
    cout<<b.c<<"\n";
    cout<<b.d<<"\n";
    cout<<b.e<<"\n";
    return 0;
}

Он будет генерировать:

[Error] 'class Base' has no member named 'd'
[Error] 'class Base' has no member named 'e'
0
ответ дан Ghulam Moinul Quadir 19 August 2018 в 16:45
поделиться
[Д2] 1. ОПРЕДЕЛЕНИЕ ПРОБЛЕМЫ РАСПРЕДЕЛЕНИЯ

Если D - производный класс базового класса B, то вы можете назначить объект типа Derived переменной (или параметру) типа Base.

ПРИМЕР

class Pet
{
 public:
    string name;
};
class Dog : public Pet
{
public:
    string breed;
};

int main()
{   
    Dog dog;
    Pet pet;

    dog.name = "Tommy";
    dog.breed = "Kangal Dog";
    pet = dog;
    cout << pet.breed; //ERROR

Хотя указанное назначение разрешено, значение, присвоенное переменной pet, теряет поле породы. Это называется проблемой нарезки.

2. КАК ИЗМЕНИТЬ ПРОБЛЕМУ СЦЕПЛЕНИЯ

Чтобы устранить проблему, мы используем указатели на динамические переменные.

ПРИМЕР

Pet *ptrP;
Dog *ptrD;
ptrD = new Dog;         
ptrD->name = "Tommy";
ptrD->breed = "Kangal Dog";
ptrP = ptrD;
cout << ((Dog *)ptrP)->breed; 

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

8
ответ дан haberdar 19 August 2018 в 16:45
поделиться
  • 1
    Я понимаю «нарезку», часть, но я не понимаю «проблему». Как проблема, что некоторое состояние dog, которое не является частью класса Pet (элемент данных breed), не копируется в переменной pet? Код интересуется только членами данных Pet - видимо. Нарезка - определенно «проблема». если это нежелательно, но я не вижу этого здесь. – curiousguy 18 February 2012 в 06:18
  • 2
    & Quot; ((Dog *)ptrP) & Quot; Я предлагаю использовать static_cast<Dog*>(ptrP) – curiousguy 18 February 2012 в 06:20
  • 3
    Я предлагаю указать, что вы сделаете строку «порода» в конечном итоге утечкой памяти без виртуального деструктора (деструктор «string» не будет вызываться) при удалении через «ptrP» ... Почему вы проявляете проблематичность? Исправление в основном относится к классу. Проблема в этом случае заключается в том, что записывать конструкторы для контроля видимости, когда наследование утомительно и легко забывается. Вы не окажетесь рядом с опасной зоной с вашим кодом, так как не существует никакого полиморфизма или даже упоминается (срез урезает ваш объект, но не приведет к сбою вашей программы здесь). – Dude 18 October 2012 в 03:58
  • 4
    -1 Это полностью не позволяет объяснить реальную проблему. C ++ имеет семантику значений, not ссылочную семантику, такую ​​как Java, поэтому все это вполне можно ожидать. И "fix" действительно является примером подлинно ужасного кода на C ++. & Quot; Крепление & Quot; несуществующие проблемы, подобные этому типу среза, прибегая к динамическому распределению, - это рецепт для багги-кода, утечки памяти и ужасной производительности. Обратите внимание, что там есть случаи, когда нарезка является плохим, но этот ответ не позволяет указать их. Подсказка: проблема начинается, если вы назначаете через ссылки . – fgp 22 January 2013 в 18:35

Проблема среза в C ++ возникает из семантики значений ее объектов, которая оставалась в основном из-за совместимости с C-структурами. Вам нужно использовать явный синтаксис ссылок или указателей для достижения «нормального» поведения объекта, обнаруженного на большинстве других языков, которые выполняют объекты, т. Е. Объекты всегда передаются по ссылке.

Короткими ответами являются то, что вы нарезаете объект путем присвоения производного объекта базовому объекту значением , то есть оставшийся объект является лишь частью производного объекта. Чтобы сохранить семантику стоимости, нарезка является разумным поведением и имеет относительно редкое применение, которое не существует на большинстве других языков. Некоторые люди считают это особенностью C ++, в то время как многие считают ее одной из особенностей / недостатков C ++.

8
ответ дан ididak 19 August 2018 в 16:45
поделиться
  • 1
    & Quot; <я> & Quot; нормальный & Quot; поведение объекта & quot; это не «нормальное поведение объекта», это reference semantic . И он никак не связан с с C struct, совместимостью или другим не-смыслом, о котором вам говорил любой случайный священник ООП. – curiousguy 27 November 2011 в 13:27
  • 2
    @curiousguy Аминь, брат. Печально видеть, как часто C ++ получает из-за того, что не является Java, когда семантика значений - одна из вещей, которая делает C ++ настолько безумно мощным. – fgp 22 January 2013 в 18:42

В C ++ объект производного класса может быть назначен объекту базового класса, но другой способ невозможен.

class Base { int x, y; };

class Derived : public Base { int z, w; };

int main() 
{
    Derived d;
    Base b = d; // Object Slicing,  z and w of d are sliced off
}

Обрезка объектов происходит, когда объект производного класса присваивается базе объект класса, дополнительные атрибуты объекта производного класса вырезаются для формирования объекта базового класса.

3
ответ дан Kartik Maheshwari 19 August 2018 в 16:45
поделиться

Я просто столкнулся с проблемой нарезки и тут же приземлился. Итак, позвольте мне добавить мои два цента к этому.

Приведем пример из «производственного кода» (или что-то вроде близкого):


Допустим, у нас есть то, что рассылает действия. Например, пользовательский интерфейс центра управления. Этот пользовательский интерфейс должен получить список вещей, которые в настоящее время могут быть отправлены. Поэтому мы определяем класс, содержащий информацию о доставке. Назовем это Action. Таким образом, Action имеет некоторые переменные-члены. Для простоты мы имеем только 2, являющиеся std::string name и a std::function<void()> f. Затем он имеет void activate(), который просто выполняет член f.

Таким образом, пользовательский интерфейс получает std::vector<Action>. Представьте себе некоторые функции, такие как:

void push_back(Action toAdd);

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

Итак, парень происходит от Action, чтобы добавить свой собственный вкус. Он передает экземпляр своего урожая в класс push_back, но затем программа переходит в haywire.

Итак, что случилось? Как вы могли предположить : объект был отрезан.

Дополнительная информация из экземпляра потеряна, а f теперь подвержен неопределенному поведению.

]

Надеюсь, что в этом примере рассказывается о тех людях, которые не могут себе представить, когда говорят о A s и B в какой-то мере.

-2
ответ дан Martin B. 19 August 2018 в 16:45
поделиться

Мне кажется, что нарезка - это не столько проблема, которая отличается от того, когда ваши собственные классы и программы плохо архивируются / разработаны.

Если я передаю объект подкласса в качестве параметра для метод, который принимает параметр суперкласса типа, я должен, конечно, знать об этом и знать внутренне, вызываемый метод будет работать только с объектом суперкласса (aka baseclass).

Мне кажется, необоснованное ожидание того, что предоставление подкласса, где запрашивается базовый класс, каким-то образом приведет к конкретным результатам подкласса, вызовет проблему разрезания. Его либо плохой дизайн при использовании метода, либо недостаточная реализация подкласса. Я предполагаю, что это обычно результат жертвовать хорошим дизайном ООП в пользу целесообразности или повышения производительности.

4
ответ дан Minok 19 August 2018 в 16:45
поделиться
  • 1
    Но помните, Минок, что вы НЕ передаете ссылку на этот объект. Вы передаете новую копию этого объекта, но используете базовый класс для его копирования в процессе. – Arafangion 22 December 2010 в 12:06
  • 2
    защищенной копии / присвоения в базовом классе, и эта проблема решена. – Dude 18 October 2012 в 03:51
  • 3
    Ты прав. Хорошей практикой является использование абстрактных базовых классов или ограничение доступа к копированию / присваиванию. Тем не менее, это не так просто определить, как только он там, и легко забыть о позаботиться. Вызов виртуальных методов с нарезанным * это может привести к таинственным вещам, если вы уйдете без нарушения доступа. – Dude 18 October 2012 в 04:06
  • 4
    Я вспоминаю из своих курсов программирования на C ++ в университете, что существуют лучшие практики, которые для каждого класса, который мы создали, мы должны были писать конструкторы по умолчанию, конструкторы копирования и операторы присваивания, а также деструктор. Таким образом, вы убедились, что построение копии и т. П. Произошло так, как вам было нужно, при написании класса ... а не позже появлялось какое-то странное поведение. – Minok 25 July 2014 в 18:24

Найти похожие ответы здесь: http://sickprogrammersarea.blogspot.in/2014/03/technical-interview-questions-on-c_6.html

Нарезка означает, что данные, добавленные подклассом, отбрасываются, когда объект подкласса передается или возвращается по значению или из функции, ожидающей объект базового класса.

Объяснение: Рассмотрим следующее объявление класса:

           class baseclass
          {
                 ...
                 baseclass & operator =(const baseclass&);
                 baseclass(const baseclass&);
          }
          void function( )
          {
                baseclass obj1=m;
                obj1=m;
          }

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

2
ответ дан Santosh 19 August 2018 в 16:45
поделиться

Большинство ответов здесь не могут объяснить, какова фактическая проблема с разрезанием. Они объясняют только доброкачественные случаи нарезки, а не предательские. Предположим, как и другие ответы, что вы имеете дело с двумя классами A и B, где B получает (публично) из A.

В этой ситуации C ++ позволяет вам передать экземпляр оператора B в A, а также в конструктор копирования. Это работает, потому что экземпляр B может быть преобразован в const A&, а именно, какие операторы присваивания и конструкторы-копии ожидают, что их аргументы будут.

Доброкачественный случай

B b;
A a = b;

Ничего плохого в этом нет - вы попросили экземпляр A, который является копией B, и это именно то, что вы получаете. Конечно, a не будет содержать некоторых членов b, но как это сделать? В конце концов, это A, а не B, поэтому даже не слышал об этих членах, не говоря уже о возможности их хранения.

вероломный случай

B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!

Вы можете подумать, что b2 будет копией b1 впоследствии. Но, увы, это не так! Если вы проверите его, вы обнаружите, что b2 - это франкенштейновское существо, сделанное из некоторых кусков b1 (куски, которые B наследует от A), и некоторые фрагменты b2 (куски что только B содержит). Ой!

Что случилось? Ну, C ++ по умолчанию не обрабатывает операторы присваивания как virtual. Таким образом, строка a_ref = b1 вызовет оператор присваивания A, а не номер B. Это связано с тем, что для не виртуальных функций объявленный тип (который является A&) определяет, какая функция вызывается, в отличие от фактического типа (который был бы B, поскольку a_ref ссылается на экземпляр B ). Теперь оператор присваивания A явно знает только о членах, объявленных в A, поэтому он будет копировать только те, оставляя члены, добавленные в B без изменений.

Решение

Присвоение только части объекта обычно имеет мало смысла, но, к сожалению, C ++ не предусматривает встроенного способа запретить это. Вы можете, однако, бросить свои собственные. Первый шаг - сделать оператор присваивания виртуальным . Это гарантирует, что он всегда является оператором присваивания фактического типа, который вызывается, а не объявленным типом. Второй шаг - использовать dynamic_cast, чтобы убедиться, что назначенный объект имеет совместимый тип. Третий шаг - выполнить фактическое присвоение в члене (protected!) assign(), так как B assign(), вероятно, захочет использовать A 's assign() для копирования A членов .

class A {
public:
  virtual A& operator= (const A& a) {
    assign(a);
    return *this;
  }

protected:
  void assign(const A& a) {
    // copy members of A from a to this
  }
};

class B : public A {
public:
  virtual B& operator= (const A& a) {
    if (const B* b = dynamic_cast<const B*>(&a))
      assign(*b);
    else
      throw bad_assignment();
    return *this;
  }

protected:
  void assign(const B& b) {
    A::assign(b); // Let A's assign() copy members of A from b to this
    // copy members of B from b to this
  }
};

Обратите внимание, что для чистого удобства B operator= ковариантно переопределяет возвращаемый тип, поскольку он знает, что он возвращает экземпляр B.

399
ответ дан splicer 19 August 2018 в 16:45
поделиться
  • 1
    IMHO, проблема в том, что существует наследование двух разных типов, которые могут подразумеваться наследованием: любое значение derived может быть присвоено коду, ожидающему значение base, или любая производная ссылка может использоваться в качестве базовой ссылки. Я хотел бы видеть язык с системой типов, которая затрагивает обе концепции отдельно. Существует много случаев, когда производная ссылка должна быть заменяемой для базовой ссылки, но производные экземпляры не должны подставляться под базовые; есть также много случаев, когда экземпляры должны быть конвертируемыми, но ссылки не должны подставляться. – supercat 12 August 2013 в 17:11
  • 2
    Я не понимаю, что так плохо в твоей «предательской». дело. Вы заявили, что хотите: 1) получить ссылку на объект класса A и 2) передать объект b1 в класс A и скопировать его материал в ссылку класса A. То, что на самом деле является неправильным, - это правильная логика данный код. Другими словами, вы взяли небольшой кадр изображения (A), поместили его на большее изображение (B), и вы нарисовали его через этот фрейм, позже пожаловавшись, что ваше более крупное изображение выглядит уродливо :) Но если мы просто рассмотрим эту рамку, это выглядит довольно хорошо, как хотел художник, верно? :) – Mladen B. 14 November 2013 в 15:05
  • 3
    Проблема, по-разному, в том, что C ++ по умолчанию принимает очень сильный вид substitutability - он требует, чтобы операции базового класса выполнялись правильно на экземплярах подкласса. И это даже для операций, которые компилятор автогенерировал как назначение. Таким образом, этого недостаточно, чтобы не испортить свои собственные операции в этом отношении, вам также необходимо явно отключить неправильные, созданные компилятором. Или, конечно, избегайте публичного наследования, которое обычно является хорошим предложением в будущем ;-) – fgp 16 November 2013 в 18:31
  • 4
    Другой распространенный подход - просто отключить оператор копирования и присваивания. Для классов в иерархии наследования обычно нет оснований использовать значение вместо ссылки или указателя. – Siyuan Ren 22 August 2014 в 11:48
  • 5
    Что за? Я понятия не имел, что операторы могут быть отмечены виртуальными – paulm 2 March 2015 в 16:23

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

Также подумал, что кто-то должен также упомянуть, что вам следует делать, чтобы избежать нарезка ... Получите копию стандартов кодирования C ++, 101 правила и рекомендации.

Он предлагает несколько сложный шаблон, чтобы полностью решить проблему: иметь защищенный экземпляр копии, защищенный чистый виртуальный DoClone и публичный клон с утверждением, которое скажет вам если (далее) производный класс не смог правильно выполнить DoClone. (Метод Clone делает правильную глубокую копию полиморфного объекта.)

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

6
ответ дан Steve Steiner 19 August 2018 в 16:45
поделиться
  • 1
    & quot; Вы также можете пометить конструктор копирования в явном явном виде & quot; который делает не вообще. – curiousguy 4 August 2012 в 23:25

Третий матч в google для «C ++ slicing» дает мне эту статью в Википедии http://en.wikipedia.org/wiki/Object_slicing и этот (нагретый, но первые несколько сообщений определяют проблему ): http://bytes.com/forum/thread163565.html

Таким образом, это когда вы назначаете объект подкласса суперклассу. Суперкласс ничего не знает о дополнительной информации в подклассе и не имеет места для его хранения, поэтому дополнительная информация получает «отрезанный».

Если эти ссылки не дают достаточной информации для «хороший ответ», пожалуйста, отредактируйте свой вопрос, чтобы сообщить нам, что еще вы ищете.

30
ответ дан The Archetypal Paul 19 August 2018 в 16:45
поделиться
class A 
{ 
    int x; 
};  

class B 
{ 
    B( ) : x(1), c('a') { } 
    int x; 
    char c; 
};  

int main( ) 
{ 
    A a; 
    B b; 
    a = b;     // b.c == 'a' is "sliced" off
    return 0; 
}
1
ответ дан Tim Cooper 19 August 2018 в 16:45
поделиться
  • 1
    Не могли бы вы дать дополнительные подробности? Как ваш ответ отличается от уже опубликованных? – Alexis Pigeon 29 November 2012 в 14:55
  • 2
    Думаю, что больше объяснений не будет плохо. – looper 29 November 2012 в 14:55

, когда объект производного класса присваивается объекту базового класса, дополнительные атрибуты объекта производного класса вырезаются (отбрасываются) из объекта базового класса.

class Base { 
int x;
 };

class Derived : public Base { 
 int z; 
 };

 int main() 
{
Derived d;
Base b = d; // Object Slicing,  z of d is sliced off
}
-1
ответ дан Varun_k 19 August 2018 в 16:45
поделиться

Проблема нарезки является серьезной, поскольку это может привести к повреждению памяти, и очень сложно гарантировать, что программа не пострадает от нее. Чтобы разработать его из языка, классы, поддерживающие наследование, должны быть доступны только по ссылке (не по значению). Язык программирования D имеет это свойство.

Рассмотрим класс A и класс B, полученный из A. Повреждение памяти может произойти, если в A-части есть указатель p и экземпляр B, который указывает p на дополнительные данные B , Затем, когда дополнительные данные удаляются, p указывает на мусор.

25
ответ дан Walter Bright 19 August 2018 в 16:45
поделиться
  • 1
    Пожалуйста, объясните, как может произойти повреждение памяти. – foraidt 8 November 2008 в 13:48
  • 2
    вызов foo () вызовет A :: foo () после нарезки, а не B :: foo () ... – Tobi 10 November 2008 в 13:53
  • 3
    Я забыл, что копия ctor сбросит vptr, мою ошибку. Но вы все равно можете получить повреждение, если A имеет указатель, а B устанавливает, что он указывает на раздел B, который вырезается. – Walter Bright 11 November 2008 в 03:21
  • 4
    Эта проблема не ограничивается нарезкой. Любые классы, содержащие указатели, будут иметь сомнительное поведение с оператором присваивания по умолчанию и copy-constructor. – Weeble 11 February 2009 в 12:54
  • 5
    @Weeble: то, что делает нарезку объектов хуже, чем общие исправления указателей, заключается в том, что, чтобы быть уверенным, что вы предотвратили нарезку, базовый класс должен обеспечить преобразование конструкторов для каждого производного класса . (Почему? Любые производные классы, которые пропущены, восприимчивы к тому, чтобы их подхватили копии ctor базового класса, поскольку Derived неявно конвертируется в Base.) Это, очевидно, противоречит принципу открытого закрывания и большому обслуживанию бремя. – j_random_hacker 24 October 2012 в 13:30

Если у вас есть базовый класс A и производный класс B, вы можете сделать следующее.

void wantAnA(A myA)
{
   // work with myA
}

B derived;
// work with the object "derived"
wantAnA(derived);

Теперь для метода wantAnA нужна копия derived , Однако объект derived не может быть полностью скопирован, так как класс B может изобретать дополнительные переменные-члены, которые не находятся в его базовом классе A.

Поэтому, чтобы вызвать wantAnA, компилятор будет «срезать» все дополнительные члены производного класса. Результатом может быть объект, который вы не хотите создавать, потому что

  • он может быть неполным,
  • ведет себя как объект A (все особые поведения класс B теряется).
134
ответ дан Will Vousden 19 August 2018 в 16:45
поделиться
  • 1
    C ++ - not Java! Если wantAnA (как следует из названия!) Хочет A, то это то, что он получает. И экземпляр A, будет, uh, вести себя как A. Как это удивительно? – fgp 22 January 2013 в 18:39
  • 2
    @fgp: Это удивительно, потому что вы не передаете функцию A . – Black 3 March 2013 в 09:03
  • 3
    @fgp: поведение похоже. Однако для среднего программиста на C ++ это может быть менее очевидным. Насколько я понял, никто не «жалуется». Речь идет о том, как компилятор справляется с ситуацией. Imho, лучше избегать нарезки вообще путем прохождения (const) ссылок. – Black 7 April 2013 в 13:13
  • 4
    @ThomasW Нет, я бы не выбрасывал наследование, но использовал ссылки. Если сигнатура wantAnA будет void wantAnA (const A & amp; myA) , тогда не было нарезки. Вместо этого передается ссылка только для чтения на объект вызывающего абонента. – Black 28 May 2013 в 08:44
  • 5
    проблема в основном связана с автоматическим кастингом, который компилятор выполняет с derived с типом A. Неявное кастинг всегда является источником неожиданного поведения на C ++, потому что часто бывает трудно понять, как локально это происходило при произведении. – pqnet 7 August 2014 в 00:15
Другие вопросы по тегам:

Похожие вопросы: