У меня есть проблема нарезки C ++. Я новичок в C ++, так что, может быть, просто слишком глуп, чтобы понять, что это невозможно сделать … Я пробовал различные обходные пути, и мой текущий лучший подход выглядит ниже. (Мне нужно сделать что-то подобное, чтобы избежать изменения тонны интерфейсов в очень большой устаревшей кодовой базе. Ни в коем случае не утверждая, что это элегантный стиль !!)
Проблемы с компиляцией. Звучит ли идея? Или весь подход обречен на провал? Конструкторы для ссылок, кажется, проблема. Я читал «Язык программирования С ++» Страуструпа (или, по крайней мере, то, что я считал соответствующими разделами), но это не помогло.
class FOO {};
class FOOSUBCLASS : public FOO {
public:
FOOSUBCLASS(const int id = 0) : _id(id) {}
private:
int _id;
};
class BAR {
public:
BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }
BAR(const FOOSUBCLASS foosc) : _foosc(foosc), _realFoo(&_foosc) {}
private:
FOO _foo;
FOOSUBCLASS _foosc;
FOO& _realFoo;
};
Компилятору не нравится мой _realFoo(&_foo)
линия. Я хотел бы ссылку на _foo
, просто чтобы быть ссылкой из переменной-члена в классе. Разве это не возможно в C ++?
Вот конкретная ошибка VS2005:
'initializing' : cannot convert from 'FOO *' to 'FOO &'
_foo
это FOO&
,
&_foo
это FOO*
,
Компилятор cannot convert from 'FOO *' to 'FOO &'
,
что ты хочешь ..., _realFoo(_foo)
Не связано: что вы, вероятно, на самом деле хотите std::unique_ptr<FOO>
член вместо. Это будет намного меньше и намного менее подвержено ошибкам.
Структура, как у вас есть сейчас, содержит полный и законченный экземпляр FOO
и полный и полный экземпляр FOOSUBCLASS
и ссылка. В наименее положить два FOO
штуковин в союзе, поэтому размер BAR
только немного больше, чем самый большой FOO
производное. Это, вероятно, будет использовать ту же память, что и unique_ptr<FOO>
, К несчастью, union
s — распространенный источник ошибок в C и C ++.
Другая проблема, если кто-то приходит и пишет
class FOOSOMETHINGELSE : public FOO {
int buffer[1024];
};
Тогда вам придется пойти и найти BAR
Класс и изменить его, сделать его еще больше, и перекомпилировать весь ваш код, который использует BAR
везде. Принимая во внимание, что если вы использовали unique_ptr<FOO>
тогда вам не придется менять BAR
или перекомпилировать что-нибудь. Так меньше вероятность ошибки.
Здесь есть несколько проблем. Вы правильно идентифицируете один из них как нарезку, но нарезка не вызывает ошибок во время компиляции (что делает его таким ужасным …). Ответ Mooing Duck должен решить вашу проблему с компиляцией, но проблема срезов остается. Предположим, у вас есть
FOO *x = new FOOSUBCLASS;
BAR y(*x);
Это приведет к нарезке, потому что будет вызван следующий конструктор:
BAR(const FOO foo) : _foo(foo), _realFoo(&_foo) { }
и он принимает свой аргумент по значению, то есть будет происходить копирование из производного в базовое.
Нарезка происходит, когда вы пытаетесь назначить объект типа производного класса объекту базового класса, например, путем передачи производного класса в функцию, которая принимает базовый класс по значению как ты здесь делаешь. По сути, любые члены-данные объекта производного класса молча «обрезаются», потому что просто нет места для размещения их в куске памяти, который достаточно велик для хранения объекта базового класса. Когда вам нужно работать с объектами, которые на самом деле могут быть производного класса, вы должен используйте либо ссылки на наши указатели (или умные указатели, такие как shared_ptr
или же unique_ptr
).
Я уверен, что все, что вы хотите сделать здесь, это позволить BAR
объект относится к объекту, который является либо FOO
объект или что-то полученное из него — правильно? В этом случае (и при условии, что время жизни FOO
объект превышает таковой из BAR
объект), все что вам нужно это:
class BAR {
public:
explicit BAR(FOO& foo) : _foo(foo) {}
private:
FOO& _foo;
};