У меня есть огромная база кода C ++, с которой я работаю.
Я хочу представить новый подкласс и использовать его во множестве различных контекстов, однако у моего обученного ума Java есть проблемы с этим в C ++.
Я хочу минимизировать изменения кода. Итак, мой основной класс интересов (BAR
ниже) имеет переменную-член класса FOO
, Я хочу сделать подкласс FOO
называется FOOSUBCLASS
, В Java это тривиально. Объекты хранятся по ссылке по умолчанию. Этот код не делает этого (как показано ниже), могу ли я массажировать этот код, не меняя интерфейсы (и не вводя ссылки), и все же заставить мое приложение работать?
class FOO {
};
class FOOSUBCLASS : FOO {
public:
FOOSUBCLASS(const int id) {_id = id;}
private:
int _id;
};
class BAR {
public:
BAR(const FOO foo) { _foo = foo;}
private:
FOO _foo;
};
Ниже мое главное:
FOOSUBCLASS fsc(1);
BAR b(fsc);
Но это не компилируется в VS2005. Это говорит:
‘type cast’: преобразование из ‘FOOSUBCLASS *’ в ‘const FOO &’существует, но недоступен
Получите ту же ошибку компилятора, если я добавлю очевидный другой конструктор BAR
BAR(const FOOSUBCLASS foo) { _foo = foo;}
Я понимаю, что C ++ будет копировать данные из FOOSUBCLASS
в объект класса FOO
, (используя оператор присваивания или его переопределенную версию) Но в моем случае у меня есть дополнительные переменные-члены в FOOSUBCLASS
(и некоторые переопределенные функции-члены), поэтому я просто не хочу, чтобы это делалось. Я хочу, чтобы моя переменная-член _foo
чтобы действительно быть типом FOOSUBCLASS
в некоторых контекстах и FOO
в других. Это вообще возможно?
Спасибо за ваши мысли.
Вы не можете сделать это так, как написали сейчас, извините. Это называется «нарезка», и больше информации об этом можно найти здесь: Что такое нарезка объектов?
Если вы хотите, чтобы ваш _foo
Чтобы член был полиморфным, вам нужно использовать указатель или ссылку. Будьте внимательны к управлению жизненным циклом, когда вы делаете такие вещи, конечно.
Сделать базовый класс общедоступным
class FOOSUBCLASS : public FOO {
public:
FOOSUBCLASS(const int id) {_id = id;}
private:
int _id;
};
Кроме того, остерегайтесь нарезки в BAR
конструктор
Назначьте указатель / ссылку, чтобы избежать этого:
class FOO
{
};
class FOOSUBCLASS : public FOO
{
public:
FOOSUBCLASS(const int id) : _id(id) {}
private:
int _id;
};
class BAR
{
public:
BAR(const FOO& foo) : _foo(foo)
{
}
private:
FOO& _foo;
};
Примечание: я использовал синтаксис списка инициализаторов вместо присваиваний в теле конструктора.
Сначала в C ++ классах по умолчанию используют private
наследовать от своих базовых классов, это означает, что FOOSUBCLASS
это FOO
но преобразование является внутренним и не доступно для вас. Итак, сначала преобразовать class FOOSUBCLASS : FOO
в class FOOSUBCLASS : public FOO
а второй в Java каждый это ссылка, так что вы можете сказать,
FOOSUBCLASS fs;
FOO f = fs;
но в C ++ у нас есть ссылки и не-ссылки и использование FOO f
создать не ссылку, которая на самом деле является объектом, так FOO f = fs
только копия FOO
часть fs
в f
и не вызывает FOO
ссылка на FOOSUBCLASS
Для достижения этого вы должны использовать указатель или ссылку или умные указатели. Например, вы можете сказать:
FOOSUBCLASS* fs = new FOOSUBCLASS;
FOO* f = fs; // Use pointer is OK
FOO& rf = fs; // A reference of fs as a FOO
std::auto_ptr<FOO> spf( fs ); // OK, but for this destructor must be virtual
В дополнение к пользователю sehe, рассмотрите возможность передачи ссылки, а не передачи по значению в конструктор BAR.
class BAR {
public:
BAR(const FOO& foo) { _foo = foo;}
private:
const FOO& _foo;
};