[C++] szablony, dziedziczenie prywatne i szalone problemy

Odpowiedz Nowy wątek
2009-01-04 00:00

Rejestracja: 17 lat temu

Ostatnio: 3 lata temu

Lokalizacja: Kielce

0

Problem to pewnie wina złych pomysłów... Ale w skrócie, mam klasę bazową będącą teoretycznie robolem oraz klase niby interfejsu wyższego poziomu. Obie te klasy to szablony. Trudno opisać cały ten bałagan, w każdym razie kod przykładowy wygląda tak:

template <typename T>
class BaseW
  {
    protected:
      T work(T a, T b) { /*tu żyją smoki*/};
    public:
      BaseW(){/*tu składają jaja smoki*/};
      ~BaseW(){/*tu giną smoki*/};
  }

template <typename T>
class WHorse: private BaseW<T>
  {
    protected:
      typedef T (BaseW::*wrk)(T,T);
      map<char,wrk> workers;
    public:
      WHorse()
        {
          workers['a']=BaseW<T>::work; // <-- Tu jest problem kompilacji
        }
      virtual ~WHorse(){/*nothing here, move on*/};
  }

Problem jaki się pojawia to jakoby brak funkcji w tym miejscu (np dla konkretyzacji z int), brzmi on:

no matching function for call to  WHorse<int>::work().
note: candidates are: T BaseW::work(T,T) [ with T = int ].

Może to mój błąd, ale wydaje mi się że powinno przyjąć normalnie... Co tu robie źle? może ewentualnie jakaś zmiana podejścia?


HAKGER - 50% Complete

Pozostało 580 znaków

2009-01-04 02:26

Rejestracja: 15 lat temu

Ostatnio: 7 lat temu

0

Mapa jako klasa nie może uzyskać dostępu do innych składowych niż publiczne, chyba że zostanie zaprzyjaźniona z daną klasą, tyczy się to także wskaźników na składowe. Do tego wypadałoby przez bieżącą, zaprzyjaźnioną klasę się do dziedziczonych metod odwoływać. To powinno zadziałać na wszystkich kompilatorach:

template <typename T>
class WHorse: private BaseW<T> {
protected:
    typedef T (BaseW<T>::*wrk)(T,T);
    map<char,wrk> workers;

    template < class, class, class, class > 
    friend class map;
public:
    WHorse() {
        workers['a'] = &BaseW<T>::work;
    }
    virtual ~WHorse() {/*nothing here, move on*/}
};

Może nie wygląda za pięknie ale z ISO jest zgodne i nawet durne kompilatory to łykają, swoją drogą G++ jest chyba najbardziej tolerancyjny.

A w ramach promocji kolejna ciekawostka z g++, która generuje uroczy komunikat o błędzie:

template<class> class bo_to_zla_struktura_byla { friend int main(); };

<font color="#7F7F7F7F" size="1">hm, (w)horse...</span>


I nie udawaj, że rozumiesz.

Pozostało 580 znaków

2009-01-04 10:14

Rejestracja: 16 lat temu

Ostatnio: 6 lat temu

0
Johnny_Bit napisał(a)

może ewentualnie jakaś zmiana podejścia?

Może coś takiego raczej:

template <typename T>
class Master
{
protected:
   class IWorker
   {
   public:
      virtual T work(T a, T b) = 0;
      virtual ~IWorker(){}
   };

   class BaseWorker : public IWorker
   {
   public:
      virtual T work(T a, T b) { /* ... */};
   };

   class ExtWorker : public IWorker
   {
   private:
      Master *master;
   public:
      ExtWorker(Master *master) { this->master = master; }
      virtual T work(T a, T b) { /* ... */; };
   };

   map<char,IWorker*> workers;
   typedef typename std::map<char,IWorker*>::iterator iterator;
public:
   Master()
   {
      workers['a'] = new BaseWorker();
      workers['b'] = new ExtWorker(this);
   }

   ~Master()
   {
      for(iterator it = workers.begin(); it != workers.end(); it++)
         delete it->second;
   }

   DoWork()
   {
      T a, b;
      for(iterator it = workers.begin(); it != workers.end(); it++)
         it->second->work(a, b);
   }
};

Pozostało 580 znaków

2009-01-04 11:13

Rejestracja: 12 lat temu

Ostatnio: 2 minuty temu

0

Masz dziedziczenie prywatne, co jest bezsensu. Popraw na dziedziczenie publiczne lub chronione i będzie po problemie.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2009-01-04 12:02

Rejestracja: 17 lat temu

Ostatnio: 3 lata temu

Lokalizacja: Kielce

0

Taka zmiana podejścia... No cóż, może być przydatna jak obecne podejście się nie spisze...

wracając do problemu:
Po zmianie już ma być wszystko ładnie, pięknie, a tu lipa. Kod:

main.cpp:

include <iostream>
#include "test.hpp"

using namespace std;

int main()
{
        WHorse<int> W;
    cout << "Hello world!" << endl;
    return 0;
}

test.hpp:

#ifndef TEST_HPP_INCLUDED
#define TEST_HPP_INCLUDED

#include <map>

template <typename T>
class BaseW
  {
    protected:
      T work(T a, T b) { /*tu żyją smoki*/return a;};
    public:
      BaseW(){/*tu składają jaja smoki*/};
      ~BaseW(){/*tu giną smoki*/};
  };

template <typename T>
class WHorse: protected BaseW<T>
  {
    protected:
      typedef T (BaseW<T>::*wrk)(T,T);
      std::map<char,wrk> workers;

      template <class, class, class, class>
      friend class std::map;

    public:
      WHorse()
        {
          workers['a']=&BaseW<T>::work;; // <-- Tu jest problem kompilacji
        }
      virtual ~WHorse(){/*nothing here, move on*/};
  };

#endif // TEST_HPP_INCLUDED

message z problemem:

test.hpp: In constructor ‘WHorse<T>::WHorse() [with T = int]’:
main.cpp:8:   instantiated from here
test.hpp:10: error: ‘T BaseW<T>::work(T, T) [with T = int]’ is protected
test.hpp:29: error: within this context

Mnie się wydaje to co najmniej dziwne... Przecież dziedziczy z base, więc do protected powinno mieć dostęp... Zmiana rodzaju dziedziczenia nie pomaga, zaprzyjaźnić maina z szablonami nie można... Właściwie pomaga tylko zmiana w base z protected na public, ale czy to miało by sens w takim wypadku? może potrzebne jakieś rzutowanie?

Edit: Po paru modyfikacjach i fajnych rozegraniach całość wygląda tak:

#ifndef TEST_HPP_INCLUDED
#define TEST_HPP_INCLUDED

#include <map>

template <typename T>
class BaseW
  {
    protected:
      T work(T a, T b) { /*tu żyją smoki*/return b;};
    public:
      BaseW(){/*tu składają jaja smoki*/};
      ~BaseW(){/*tu giną smoki*/};
  };

template <typename T>
class WHorse: protected BaseW<T>
  {
    protected:
      typedef T (BaseW<T>::*wrk)(T,T);
      std::map<char,wrk> workers;

      template <class, class, class, class>
      friend class std::map;

    public:
      WHorse()
        {
          workers['a']=&WHorse<T>::work;
        }
      virtual ~WHorse(){/*nothing here, move on*/};
      T DoWork(char cCmd, T CurrVal, T Param) { return (this->*workers[cCmd])( CurrVal, Param ); }
  };

#endif // TEST_HPP_INCLUDED

i działa jak złoto... tylko czemu nie chciał załapać BaseW zamiast WHorse..

p.s. WHorse od workhorse...


HAKGER - 50% Complete

Pozostało 580 znaków

2009-01-04 16:23

Rejestracja: 15 lat temu

Ostatnio: 7 lat temu

0

Dziedziczysz prywatnie + klasa bazowa nie jest z mapą zaprzyjaźniona, zaprzyjaźnienie nie działa wstecz.
@MarekR22, przy dziedziczeniu chronionym też będzie konieczne zaprzyjaźnianie klas...


I nie udawaj, że rozumiesz.

Pozostało 580 znaków

2009-01-05 16:31

Rejestracja: 12 lat temu

Ostatnio: 2 minuty temu

0

@deus: że co? Wytłumacz mi o co ci chodzi bo nie rozumiem po co przyjaźń z mapą? Przyjaźń z mapą nie ma ty nic do rzeczy (można ją skasować).
Problem siedzi w zastosowaniu kwalifikatora i tym, że metoda jest zadeklarowana jako protected.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2009-01-05 16:41

Rejestracja: 15 lat temu

Ostatnio: 7 lat temu

0

Że co? A o czym ja niby napisałem i w tym i w pierwszym poście? Jedynie klasy zaprzyjaźnione mogą uzyskać dostęp do chronionych składników, nawet jeżeli chodzi tylko o pointery na metody. Mówimy o przypadku użycia mapy, nie ogólnym.

Z punktu widzenia mapy nie ma różnicy jakie jest dziedziczenie i jaka jest widoczność jeżeli metoda nie będzie dostępna publicznie.


I nie udawaj, że rozumiesz.

Pozostało 580 znaków

2009-01-05 17:42

Rejestracja: 12 lat temu

Ostatnio: 2 minuty temu

0

pierwszy post jest też bez sensu. Coś ci się pomieszało z tymi ograniczeniami dostępu i przyjaźniami.
mapa powinna być przyjacielem klasy jedynie w momencie, gdy jeden z argumentów tego szablonu (klucz, wartość) jest klasą nie posiadającą publicznego copy-constructora lub operator< dla klucza jest niepubliczny. To są jedyne metody klas, których używa mapa.
Tu masz w zasadzie typy proste: char (klucz) i wskaźnik na metodę (wartość), więc mapa ma dostęp do wszystkiego co potrzebuje.


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

2009-01-05 17:45

Rejestracja: 15 lat temu

Ostatnio: 7 lat temu

0

Bez sensu to jest to Twoje trucie... Polecam douczyć się jak wyglądają prawa dostępu i wskaźniki ma metody. Nie, mapa nie ma dostępu, wartość jest wskaźnikiem na element niepubliczny - nic poza klasą i zaprzyjaźnionymi z nią nie może tego używać.
Nie ma znaczenia gdzie ta mapa jest... Spróbujem z najprostszym przykładem:

class zuo {
public:    void publiczna() {};
protected: void chroniona() {};
};

int main() {
  void(zuo::*metoda1)() = &zuo::publiczna; // przejdzie, metoda jest dostępna
  void(zuo::*metoda2)() = &zuo::chroniona; // nie przejdzie, nie jest dostępna publicznie
}

A napisać napisałeś prawie dobrze... Wartość musi być elementem publicznie dostępnym. Ja uważam sprawę za zakończoną, jak chcesz się dalej ośmieszać to pogadaj z Ranidesem lub quetzalcoatlem.


I nie udawaj, że rozumiesz.

Pozostało 580 znaków

2009-01-05 17:58

Rejestracja: 12 lat temu

Ostatnio: 2 minuty temu

0

eee a gdzie tu twoja mapa i przyjaźń z mapą?
Sorry, ale nic nie mam do ciebie, ale moim zdaniem coś namieszałeś - może najpierw przeczytaj swoje posty.

deus napisał(a)

Mapa jako klasa nie może uzyskać dostępu do innych składowych niż publiczne, chyba że zostanie zaprzyjaźniona z daną klasą, ...


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.

Pozostało 580 znaków

Odpowiedz

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