Przesłanianie metod wirtualnych

0

Witam,

W C++ generalnie nie da się przesłonić metody wirtualnej (chyba, że w tym nowym standardzie, którego nie znam jeszcze), ale co sądzicie o zastosowaniu takiego triku w celu umożliwienia takiego przesłonienia?

class A {
public:
    virtual void method();
}

class B : public A {
public:
    void method(int = 0);
}

Wtedy method w klasie B nie implementuje metody wirtualnej z klasy A ponieważ mamy tu do czynienia z innym zestawem argumentów. Co więcej nie zachodzi żadna niejednoznaczność przy wywoływaniu metody z klasy B.
Możemy nawet metodę void method(int = 0) uczynić wirtualną i w ten sposób wszystkie klasy pochodne po B będą mogły sobie wybrać czy implementować metodę z klasy B czy z A.
Czy standard mówi coś na ten temat?

Przykład zastosowania. Mamy abstrakcyjny Kontener i dziedziczące po nim Set i List. Kontener ma metodę

ConstIterator insert(const T&)

, która zwraca iterator na nowo dodany element. Z uwagi, że pewne kontenery (jak Set) mogą udostępniać tylko ConstIterator (co by nie zmienić elementu i nie zaburzyć porządku w zbiorze) to nasz abstrakcyjny Container też musi zwracać ConstIterator.
Jednak nasza klasa List chciałaby udostępniać nam zwykły Iterator zezwalający na edycję wskazywanego elementu. Posiada wiec metodę przesłaniającą insert z klasy Kontener

Iterator insert(const T&, int = 0)

.

Co sądzicie o takim sztucznym przesłanianiu metod wirtualnych?

I drugie szybkie pytanie na zbliżony temat. Jak się mają argumenty domyślne do metod wirtualnych? Weźmy taki podobny do poprzedniego przykład:

class A {
public:
    virtual void method(int);
}

class B : public A {
public:
    void method(int = 0);
}

Czy możemy korzystając ze wskaźnika A* w wywołać metodę w taki sposób? Przypuszczam, że nie, ale są jakoś skonkretyzowane zasady tym rządzące?

A* a = new B;
a->method();

Albo odwrotnie:

class A {
public:
    virtual void method(int = 0);
}

class B : public A {
public:
    void method(int);
}

I znów:

A* a = new B;
a->method();
0

Nie da się bo void method(int = 0) jest już legalną konstrukcją języka i ma swoje znaczenie. Osobiście nie widzę sensu stosowania czegoś takiego, a powodowało by to tylko błędy.

0

Nie wiem na które z pytań to była odpowiedź. :)

0
winerfresh napisał(a):

i ma swoje znaczenie
Tzn. jest zarezerwowane? Do czego?

Co sądzicie o takim sztucznym przesłanianiu metod wirtualnych?
Można. W przedstawionym przykładzie z iteratorami no może faktycznie miałoby to ręce i nogi, ale generalnie nie polecam. Im mniej "haków" tym lepiej. Innym miejscem gdzie by mógł być potrzebny taki trick to jakaś specyficzna sytuacja przy statyczny polimorfizmie. Raczej unikać, chodź z rzadka faktycznie może być zbawienne.

Co do drugiej części pytania - metodę wołasz na wskaźniku typu A* czyli pod uwagę będzie wzięty interfejs klasy A - jeśli w tej klasie parametr ma zdefiniowaną wartość domyślną to będzie można z niej skorzystać, jeśli nie - to nie.

0
adf88 napisał(a):

Co do drugiej części pytania - metodę wołasz na wskaźniku typu A* czyli pod uwagę będzie wzięty interfejs klasy A - jeśli w tej klasie parametr ma zdefiniowaną wartość domyślną to będzie można z niej skorzystać, jeśli nie - to nie.

Czyli jeśli wskaźnik w rzeczywistości pokazuje na obiekt typu B, a deklaracja metody w B nie zawiera argumentów domyślnych to w przypadku ich nie podania zostaną podstawione wartości domyślne z deklaracji wewnątrz klasy A?

0
Platyna napisał(a):
adf88 napisał(a):

Co do drugiej części pytania - metodę wołasz na wskaźniku typu A* czyli pod uwagę będzie wzięty interfejs klasy A - jeśli w tej klasie parametr ma zdefiniowaną wartość domyślną to będzie można z niej skorzystać, jeśli nie - to nie.

Czyli jeśli wskaźnik w rzeczywistości pokazuje na obiekt typu B, a deklaracja metody w B nie zawiera argumentów domyślnych to w przypadku ich nie podania zostaną podstawione wartości domyślne z deklaracji wewnątrz klasy A?

Argumenty domyślnie są wstawiane podczas kompilacji. Metody wirtualne działają podczas wykonania programu. Zatem kompilator nie ma żadnej wiedzy o faktycznym typie obiektu, zawsze stosuje znany mu interfejs klasy bazowej. Dlatego użyje argumentów domyślnych z deklaracji klasy bazowej.

0

Takie przesłanianie to błąd programistyczny.
Żeby go uniknąć wymyślono nawet słowo kluczowe "override".
Oczywiście jeśli napiszesz w komentarzu że zrobiłeś to intencjonalnie to jest szansa że Cię nikt nie ukrzyżuje.
Ale i tak, jeśli użyjesz nieodpowiedniego dostępu (przez v-table) to pewnie się wywoła metoda przesłoniona a nie przesłaniająca.

Radziłbym raczej dodać nową metodę z nową nazwą - żeby nie mylić się.

1 użytkowników online, w tym zalogowanych: 0, gości: 1