У меня есть квест вокруг таких сотрудников.C++: как предотвратить разрушение объектов, построенных в аргументе?
Существует класса А, который имеет объект типа класса B, как это член. Поскольку я хотел бы, чтобы B был базовым классом группы других классов, мне нужно использовать указатель или ссылку на объект, а не его копию, чтобы правильно использовать виртуальные методы B внутри A. Но когда я пишу такой код
class B
{public:
B(int _i = 1): i(_i) {};
~B()
{i = 0; // just to indicate existence of problem: here maybe something more dangerous, like delete [] operator, as well!
cout << "B destructed!\n";
};
virtual int GetI() const {return i;}; // for example
protected:
int i;
};
class A
{public:
A(const B& _b): b(_b) {}
void ShowI() {cout <<b.GetI()<<'\n';};
private:
const B& b;
};
и использовать его таким образом
B b(1);
A a(b);
a.ShowI();
работает отлично:
1
B destructed!
Но
A a(B(1));
a.ShowI();
дают очень нежелательный результат: объект b создает, а ab устанавливается как рефери nce, но только после того, как конструктор A закончен, объект b разрушает! Выход:
B destructed!
0
Я повторяю еще раз, что, используя копию вместо ссылки на б в A
class A
{public:
A(B _b): b(_b) {}
void ShowI() {cout <<b.GetI()<<'\n';};
private:
B b;
};
не будет работать, если B является базовым классом и называет это виртуальная функция. Возможно, я слишком глуп, потому что не знаю, не знаю, как правильно писать код, чтобы он работал отлично (тогда мне очень жаль!), Или, может быть, это совсем не так просто :-(
Конечно , если B (1) был отправлен функции или методу, а не конструктору класса, он работал идеально. И, конечно, я могу использовать тот же код, что и в this, как описано here, чтобы создать B как правильно клонируемую базу или производный объект, но не оказывается слишком сложно для такой простой ищет проблемы? а что, если я хочу использовать класс B, что я не мог изменить?
Я никогда не слышал о повышении общих указателей до ... Не могу увидеть, должен ли я когда-нибудь вызывать удаление объекта общего указателя p и если эта модель будет работать, если я использую 'DerivedFromB b; OwnsPolymorphics владеет (b); вместе с «OwnsPolymorphics» (новый DerivedFromB); потому что это не будет, если я использую обычный указатель 'B * p;' и «удалить p» в деструкторе. – Nick
Вам не нужно вызывать 'delete'. Умный указатель выполнит эту работу для вас, если ее деструктор вызывается деструктором содержащегося объекта. Он не будет работать для 'DerivedFromB b; OwnsPolymorphics владеет (b); '- этот код, похоже, не имеет большого смысла. Просто сделайте 'OwnsPolymorphics owns (новый DerivedFromB); вместо этого. Там * есть * способы заставить его работать (например, использовать пользовательский делетер с 'shared_ptr'), но все они сделают интерфейс более уродливым. Вы должны четко понимать интерфейс - какова цель этого другого способа строительства? –
Извините, идея моего примера состояла в том, чтобы обе конструкции, упомянутые в вопросе «A a (B (1)); и "B b (1); A a (b);" работает должным образом. Например, я могу написать «double b = 2.0; double c = b ** b; cout << sqrt (b);» а также «double b = 2.0; cout << sqrt (b * b)»; без ошибок. Большое вам спасибо за предложение, но если это невозможно, сделайте обе работающие, я бы предпочел свой вариант без умных указателей. – Nick