препратка към абстрактен клас

Какво означава, когато има препратка към абстрактен клас? Намерих го в код и не мога да го разбера.

Мислех, че абстрактен клас не може да бъде създаден. Как можете да го дадете за справка?


person lital maatuk    schedule 16.02.2011    source източник
comment
Този въпрос е твърде неясен. Публикувайте примерен код и обяснете защо ви обърква.   -  person aschepler    schedule 16.02.2011
comment
Може ли това да означава, че може да има някой от конкретните подкласове в другия край?   -  person Piskvor left the building    schedule 16.02.2011


Отговори (4)


Препратката към абстрактен клас е точно като указател към абстрактен клас: тя трябва да препраща към обект от някакъв неабстрактен подклас на абстрактния клас. Можете да използвате препратка като тази, за да извикате виртуални методи на посочения клас, като използвате синтаксиса ., по начин, подобен на указател към интерфейс в Java.

person Jeremiah Willcock    schedule 16.02.2011

Абстрактен клас е предназначен да бъде извлечен от. Принципът на заместване на Лисков грубо заявява, че всичко, което използва абстрактните части на типове, извлечени от абстрактна база, трябва да работи еднакво добре, използвайки базата полиморфно. Това означава, че трябва да се използва препратка или указател към основата.

person Johann Gerell    schedule 16.02.2011
comment
+1 за свързването му с принципа на заместване на Лисков. Такива ценни съвети насочват начинаещите да изследват в по-дълбоките области на софтуерното проектиране/програмиране, което води до по-компетентни колеги в съседните кабини :) - person Alok Save; 16.02.2011
comment
@Als: +1 за осъзнаване на по-дългосрочната полза от разбирането на Лисков. ;-) - person Johann Gerell; 17.02.2011

class Abstract
{
public:
  virtual void foo() = 0;
};

class Implementation : public Abstract
{
public:
  void foo() { std::cout << "Foo!" << std::endl; }
};

void call_foo(Abstract& obj) { obj.foo(); } 

int main()
{
  Abstract *bar = new Implementation();

  call_foo(*bar);

  delete bar;
}

bar е pointer към абстрактен клас. Може да се дереферира с помощта на оператора * и да се предаде като reference в call_foo, защото това е, което call_foo иска (Abstract* ще иска указател, докато Abstract& иска препратка).

В горното препратката към абстрактния клас се предава и когато foo() се извиква с помощта на . нотация (вместо указател -> нотация), той отпечатва Foo!, защото това е, което Implementation прави.

Надявам се това да помогне.

person James    schedule 16.02.2011
comment
Разбира се, дори не е необходимо да създавате указател тук. Можете щастливо да замените Abstract *bar = new Implementation(); с Abstract &bar = Implementation(); или дори лента за изпълнение; - person DanDan; 16.02.2011
comment
В този случай, да, но аз просто показвах разликите / приликите между указатели и препратки. :) - person James; 16.02.2011

Препратките в c++ се държат (почти) като скрити указатели. По-специално, същото полиморфно поведение, което можете да получите с указател, можете да го постигнете с препратка. Тоест, следните са (почти) еквивалентни

int *i = &a;
int &j = a;

ако приемем, че a е цяло число, дефинирано някъде в предишните редове. Следващите срещания на препратката j са напълно еквивалентни на срещанията на (*i). Основната разлика е, че препратката не ви създава болката от управлението на паметта, докато указателят го прави (ваша отговорност е да обработвате нови(и) и изтрити(я)). Също така, указателят не трябва да сочи към нещо, докато препратката не може да съществува, ако не препраща към нищо (1). Освен това, можете да смятате, че се държат по същия начин.

Следователно е абсолютно законно да има препратка към абстрактен обект. Ще го намерите често в сигнатури на функции, където полиморфното поведение може да бъде постигнато или с препратки, или с указатели. Но препратките дават по-лек синтаксис, както показва следната част от кода

A a;
A* ptr = &a;
A& ref = a;
ref();
ptr->operator()();
(*ptr)();

като се приеме, че клас А претоварва operator ().

(1) Е, можете да имате висящи препратки, точно като указатели:

int* a = new int(1);
int& b = *a;
delete a; // et-voila, b is now dangling.

но те не могат да бъдат създадени без да се присвои нещо, към което могат да се отнасят.

person bartgol    schedule 19.02.2012
comment
Браво за споменаването, че препратките са (почти) указатели зад решетките. - person peterh; 14.08.2020