powered by simpleCommunicator - 2.0.59     © 2025 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / C++ [игнор отключен] [закрыт для гостей] / Предварительная инициализация ссылочной переменной абстрактного класса
16 сообщений из 16, страница 1 из 1
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340619
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Доброго времени суток.

Имеется абстрактный класс Record, от которого унаследованы не виртуальные классы Comment и Shape_definition.
Я бы хотел написать примерно такой код:
Код: plaintext
1.
2.
3.
Record& record = [???]; // как-то инициализировать переменную
cin >> record;
record.draw(); // виртуальная функция, переопределённая в Comment и Shape_definition.


Я переопределил операторы >> для каждого класса. Тот, который относится к Record, предварительно выглядит так:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
std::istream& operator >> (std::istream& istr, Bushman::shp::Record& rec){
	if(!istr) throw std::runtime_error("Invalid the input stream condition.");
	char c = 0;
	istr >> c;
	if(!istr) throw std::runtime_error("Input error.");
	istr.unget();
	if(c == Bushman::shp::comment_marker){
		Bushman::shp::Comment comment;
		istr >> comment;
		rec = comment;
	}
	else if(c == Bushman::shp::header_marker){
		Bushman::shp::Shape_definition def;
		istr >> def;
		rec = def;
	}
	else{
		throw std::runtime_error("Unexpected character. The ';' or '*' expected.");
	}
	return istr;
}


Т.е. в зависимости от того, что во входном потоке, выполняется оператор >> либо для Comment, либо для Shape_definition, сохраняя полученное значение в record.

Однако, как известно, создать объект абстрактного класса нельзя. Отсюда вопрос: как бы мне правильней инициализировать Record& record? Можно, конечно попробовать как-то так:
Код: plaintext
1.
2.
3.
Record& record = Comment();
//или
Record& record = Shape_definition();


Но что-то мне этот способ не нравится... Могут ли быть какие-то подводные камни в случае использования этих вариантов?

Спасибо.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340766
Фотография Анатолий Широков
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
class Record {
public:
    virtual ~Record() {}
    virtual read(std::istream &in) = 0;
};

std::unique_ptr<Record> readRecord(std::istream &in) {
      // считываем из потока некоторый маркер класса
      std::string cls;
      in >> cls;
      std::unique_ptr<Record> record;
      if( cls == "comment" ) {
           record.reset(new Comment(...));
      } else {
      if( cls == "shape" ) {
           record.reset(new Shape(...));
      } else {
          throw "unknown class";
      }
      record->read(in);
      return record;
}
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340847
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
мне бы не хотелось использовать в данном случае указатели и сборщик мусора. Указанный мною выше способ может вызывать проблемы? Если "да", то какие?
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340853
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositumмне бы не хотелось использовать в данном случае указатели и сборщик мусора. Указанный мною выше способ может вызывать проблемы? Если "да", то какие?

Какой-такой сборщик мусора ?
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340857
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
MasterZivКакой-такой сборщик мусора ?
обыкновенный .
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340865
Фотография Анатолий Широков
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

по стандарту можно инициализировать только константную ссылку временным объектом:

Код: plaintext
1.
const Record& record = Comment();



А так, я не очень понял твою задумку - ну инициализируешь ты ссылку, дальше что? ну прочтешь данные - а что после с этим объектом-то будет?
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340887
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Анатолий ШироковА так, я не очень понял твою задумку - ну инициализируешь ты ссылку, дальше что?
дальше читаю нужные данные из потока, назначая результат этой самой ссылке.
Анатолий Широковну прочтешь данные - а что после с этим объектом-то будет?
Ничего, будет жить, пока ссылочная переменная находится в области видимости.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340896
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Анатолий ШироковА так, я не очень понял твою задумку
Задумка в том, чтобы воспользоваться полиморфизмом. Поскольку переменная является ссылкой на базовый класс, то виртуальный метод draw будет вызван на объекте реального класса. На основании маркера класса, возвращается экземпляр нужного (по контексту) производного класса.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340906
Фотография Анатолий Широков
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Перечитал твой первый пост. Возникает единственный вопрос - а зачем ты вообще наследование используешь, если у тебя все "свалено" в Record? У тебя operator>> оперирует знаниями о природе классов Comment и Shape_definition. Тебя вот это не смущает?
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340935
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Анатолий ШироковУ тебя operator>> оперирует знаниями о природе классов Comment и Shape_definition. Тебя вот это не смущает?
Откровенно говоря, смущает... Я бы хотел, чтобы эти классы имели общий интерфейс, соответственно получается, что они должны иметь общего родителя. Оператор >> должен на основании маркера автоматом распознавать, экземпляр какого именно дочернего класса должен создаваться. В результате у меня получилась такая петрушка... Если у тебя есть идея, как это реализовать более грамотно - буду признателен.

Спасибо.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340944
sherzod_
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
CompositumДоброго времени суток.

Но что-то мне этот способ не нравится... Могут ли быть какие-то подводные камни в случае использования этих вариантов?

Спасибо. Тут не подводный камень. Тут большой подводно-надводный слон. Суть полиморфизма в том что используется ССЫЛКА или УКАЗАТЕЛЬ который УКАЗЫВАЕТ на объект реализующий абстрактный интерфейс. То есть _никакого копирования_, просто _инициализация ссылки_ или _присвоение (или инициализация) указателя_.

Полиморфизм:

Код: plaintext
1.
2.
3.
Obj = Factory->CreateObj(cin); // Объект создался
Ref  ------------------->  Obj // Ссылка инициализировалась:   Object & obj = Factory->CreateObj(cin);
Ref->draw();


А вы пытаетесь сделать так:

Код: plaintext
1.
2.
3.
4.
5.
TempObj = Create();
Ref --------------------> TempObj;
Obj = Factory->CreateObj();
TempObj = Obj; // Copy Constructor WTF?
Ref ?
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340945
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Пока что мне приходит в голову только вынос этого кода из абстрактного класса в отдельный класс, являющийся оболочкой над потоком:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
namespace Bushman{
	namespace shp{
		class Shp_istream{
		private:
			std::istream& is;
		public:
			Shp_istream(std::istream& istr);
			Shp_istream& operator >> (Record& rec);
		};
	}
}
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340961
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
sherzod_,

Честно говоря, я не понял. Ссылка является константной, т.е. она указывает всегда на одну и ту же ячейку памяти, в то время как указателю можно переназначать др. адреса. Когда я назначаю ссылке новое значение, то это новое значение записывается по адресу, на который указывает ссылка, перезаписывая старое значение. Если бы я использовал указатель, но назначая ему новое значение, я бы, тем самым, назначил ему лишь другую ячейку памяти, на которую он ссылается.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38340984
Фотография Анатолий Широков
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Compositum,

Ну, в своем первом посте я как раз показал как бы я действовал:

1. создал бы абстрактый класс Record только с чисто виртуальными функциями - это интерфейс

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
class Record {
public:
     virtual ~Record() {}
     virtual std::istream& read(std::istream& in) = 0;
     virtual std::ostream& write(std::ostream& out) const = 0;
     virtual void draw() = 0;
};


2. создал бы конкретный наследников

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
class Comment : public Record {
      std::string comment;
public:
      override std::istream& read(std::istream& in) {
           in >> comment;
      }
      ...
};


3. создал бы фабричный метод, читающий из потока и создающий по префиксу тот или иной объект

Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
std::unique_ptr<Record> readRecord(std::istream &in) {
      // считываем из потока некоторый маркер класса
      std::string cls;
      in >> cls;
      std::unique_ptr<Record> record;
      if( cls == "comment" ) {
           record.reset(new Comment(...));
      } else 
      if( cls == "shape" ) {
           record.reset(new Shape(...));
      } else {
          throw "unknown class";
      }
      record->read(in);
      return record;
}



4. ну и напоследок все это связал

Код: plaintext
1.
2.
std::unique_ptr<Record> record = readObject(std::cin);
record->draw();



Вот это и был бы чистый ООП в действии.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38341007
Фотография Compositum
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Анатолий Широков,

Спасибо. Я внёс изменения в грамматику. Было:

Код: sql
1.
2.
3.
4.
5.
...
(* comment block, or shape definition *)
record = { comment line } | shape definition;

shp file data = { record };


Стало так:
Код: sql
1.
2.
3.
4.
5.
...
(* comment block, or shape definition *)
record = { comment line }, [shape definition];

shp file data = { record };


Такой подход получается более простым и надёжным, чем тот, что я выбрал ранее. Исправленная версия грамматики подразумевает, что объект класса Record содержит в себе по экземпляру классов Comment и Shape_definition. Т.о. я избавился от иерархии наследования. Соответственно и фабрика не понадобится.

Всем спасибо.
...
Рейтинг: 0 / 0
Предварительная инициализация ссылочной переменной абстрактного класса
    #38341354
Фотография MasterZiv
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Давай вот это вот ещё раз обсудим.

CompositumСсылка является константной, т.е. она указывает всегда на одну и ту же ячейку памяти, в то время как указателю можно переназначать др. адреса. Когда я назначаю ссылке новое значение, то это новое значение записывается по адресу, на который указывает ссылка, перезаписывая старое значение. Если бы я использовал указатель, но назначая ему новое значение, я бы, тем самым, назначил ему лишь другую ячейку памяти, на которую он ссылается.

Всё правильно, про это тебе и говорил sherzod_ .
Присвоил -- прощай полиморфизм.

Тем более что так присваивать ссылке очень опасно -- может быть срезка.

Record& record = Comment();
// record теперь может указывать не на Record, а на его наследника.
someOtherRecord = OtherComment();
// someOtherRecord допустим указывает теперь на Record базовый.

record = someOtherRecord; // вот тут будет происходит срезка.
...
Рейтинг: 0 / 0
16 сообщений из 16, страница 1 из 1
Форумы / C++ [игнор отключен] [закрыт для гостей] / Предварительная инициализация ссылочной переменной абстрактного класса
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]