Какво означава, когато има препратка към абстрактен клас? Намерих го в код и не мога да го разбера.
Мислех, че абстрактен клас не може да бъде създаден. Как можете да го дадете за справка?
Какво означава, когато има препратка към абстрактен клас? Намерих го в код и не мога да го разбера.
Мислех, че абстрактен клас не може да бъде създаден. Как можете да го дадете за справка?
Препратката към абстрактен клас е точно като указател към абстрактен клас: тя трябва да препраща към обект от някакъв неабстрактен подклас на абстрактния клас. Можете да използвате препратка като тази, за да извикате виртуални методи на посочения клас, като използвате синтаксиса .
, по начин, подобен на указател към интерфейс в Java.
Абстрактен клас е предназначен да бъде извлечен от. Принципът на заместване на Лисков грубо заявява, че всичко, което използва абстрактните части на типове, извлечени от абстрактна база, трябва да работи еднакво добре, използвайки базата полиморфно. Това означава, че трябва да се използва препратка или указател към основата.
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
прави.
Надявам се това да помогне.
Препратките в 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.
но те не могат да бъдат създадени без да се присвои нещо, към което могат да се отнасят.