Skocz do zawartości


klasy


8 odpowiedzi w tym temacie

#1 spike

    Pomocna dłoń

  • Super użytkownicy
  • 181 Postów:

Napisano pon, 14 mar 2016 - 10:29

Dobra miałem pewien problem ze strony kompilatora C++

struktura klas:
cpp

class A
{
public:
   A(){ b = new B; c = new C;}
   B* b;
   C* c;
};
 

Teraz magiczne zdanie:
Chciałem dostać się z klasy B do klasy C.

Główkowałem cały dzień jak to zrobić, kombinowałem z interfejsami (w delphi/fpc to nie problem) ale poległem.
Przyszedł mi jednak pewien pomysł na rozwiązanie problemu.
Przekazanie instancji klasy A do pozostałych klas czyli B i C przez konstruktor.

Czyli tu mamy błędny kod:
cpp

B::B(A* base)
{
}
 
C::C(A* base)
{
}
 

Ponieważ musimy do plików nagłówkowych klas B i C dołączyć plik nagłówkowy klasy A który zawiera w sobie dołączone pliki nagłówkowe klas B i C.

Więc jak?
W ukochanym Object Pascalu mamy wskaźnik niejawny : Pointer; 4 bajtowy.
W C++ odpowiednikiem jest "void* zmienna;"

Ta, wielu więc napisze: to proste więc zamieńmy w konstruktorach A* na void* i po sprawie...
Ne ne ne

Kompilatorek wywali błąd konwersji :)
I tu szczena mi opadła :(

Ale coś musi być, aby to działało i jest:
static_cast

więc tak piszę w/g plików:
"a.h"
cpp

#include "B.h"
#include "C.h"
 
class A
{
public:
  A();
  B* b;
  C* c;
}
 


"a.cpp"
cpp

#include "A.h"
A::A()
{
  b = new B(this);
  c = new C(this);
}
 


Teraz pliki pozostałych klas:
"b.h"
cpp

 
class B
{
public:
  B( void* base);
 
}
 


"b.cpp"
cpp

#include "B.h"
#include "A.h"
 
A* mA;
B::B(void* base)
{
  mA = static_cast<A*>(base);
}
 



"c.h"
cpp

 
class C
{
public:
  C( void* base);
  void test();
}
 


"c.cpp"
cpp

#include "C.h"
#include "A.h"
#include <iostream>
 
A* mA;
C::C(void* base)
{
  mA = static_cast<A*>(base);
 
}
 
void C::test()
{
std::cout << "Witaj świecie \n";
}
 


Teraz w metodach klasy B możemy używać zapisu:
cpp

  mA->c->test();
 



Komuś może się przydać taka konstrukcja kodu.

#2 Kaczus

    Bywalec

  • Użytkownicy
  • 36 Postów:

Napisano wto, 15 mar 2016 - 11:08

Ojojoj... W C++ void * należy używac w ostateczności (czyli uzycie takiego to z prawdopodobieństwem 1 użycie błędne).
Dodatkowo zmienne globalne... brrr....

Podpowiedć, np plik c.h może wyglądac tak:

cpp
class A;
class C
{
public:
  C( A* base);
  void test();
}


#3 spike

    Pomocna dłoń

  • Super użytkownicy
  • 181 Postów:

Napisano wto, 15 mar 2016 - 16:03

Testowałeś to ?
Możesz podać działający przykład?
Albo nie umiem i nie działa, albo gdzieś popełniłeś błąd.

Cel to dostęp do klasy, która nas (klasę) stworzyła.
Czyli w plikach nagłówkowych klas: B i C nie mogę dołączać pliku nagłówkowego klasy A, ponieważ jej plik nagłówkowy dołącza pliki nagłówkowe klas B i C.

Czyli w tych plikach nie dam rady stworzyć zmiennej wskaźnikowej na klasę A.
A chcę wykorzystać właśnie funkcje tej klasy.
Więc potrzebna mi jej instancja klasy A wewnątrz klas B i C.

Odnośnie tego co mi napisałeś kodu to kompilator wypluwa mi błąd przy tworzeniu obiektu C:

cpp

c = new C(this);
 


odnośnie "Braku dopasowania funkcji dla wywołania C::C(A* const); "
rozumiem, że konwersję można spróbować zrobić ale też mi to nie chce działać.

Natomiast co do samego wskaźnika, to można w sekcji prywatnej klasy C stworzyć wskaźnik np. "void* baseClass;" i w konstruktorze przypisać:
cpp

this->baseClass = base;
 


po czym każdorazowe użycie dostępu do nadklasy :) wiąże się z takową wiązanką kodu:
cpp

A* aClass = static_cast<A>(this->baseClass);
//  aClass->b->test();
 


co można w prywatną funkcję obudować.

#4 Kaczus

    Bywalec

  • Użytkownicy
  • 36 Postów:

Napisano śro, 16 mar 2016 - 13:28

Tak korzystam z tego czasami i to działa. Podaj kod, oraz to co Ci zwraca kompilator - dokładnie, bo coś masz widocznie nie tak.

#5 spike

    Pomocna dłoń

  • Super użytkownicy
  • 181 Postów:

Napisano śro, 16 mar 2016 - 20:16

OK, dam przykład który wywala w konstruktorze klasy w pliku AClass.cpp z komunikatem:

Cytat

no matching function for call to 'BClass::BClass(AClass* const)'|

cpp

this->bClass = new BClass(this);
 

A to całość:
main.cpp
cpp

#include "AClass.h"
 
int main()
{
    AClass* aClass = new AClass;
 
    delete aClass;
}
 

AClass.h
cpp
#ifndef ACLASS_H
#define ACLASS_H
 
#include "BClass.h"
#include "CClass.h"
 
class AClass
{
    public:
        AClass();
        virtual ~AClass();
        BClass* getBClass();
        CClass* getCClass();
    protected:
    private:
        BClass* bClass;
        CClass* cClass;
};
 
#endif // ACLASS_H

AClass.cpp
cpp
#include "AClass.h"
 
AClass::AClass()
{
    this->bClass = new BClass(this);
    this->cClass = new CClass(this);
}
 
AClass::~AClass()
{
    //dtor
}
 
BClass* AClass::getBClass();
{
    return this->bClass;
}
 
Class* AClass::getCClass();
{
    return this->cClass;
}
 
 

BClass.h
cpp
#ifndef BCLASS_H
#define BCLASS_H
 
class pAClass;
 
class BClass
{
    public:
        BClass(pAClass* _AClass_);
        virtual ~BClass();
        void testFunction();
    protected:
    private:
        pAClass* _aClass;
};
 
#endif // BCLASS_H
 
 

BClass.cpp
cpp
#include "AClass.h"
 
BClass::BClass(pAClass* _AClass_)
:_aClass(_AClass_)
{
    // this->_aClass = _AClass_;  /\ UP /\
}
 
BClass::~BClass()
{
    //dtor
}
 
void BClass::testFunction()
{
    std::cout << "test Function message";
}

CClass.h
cpp
#ifndef CCLASS_H
#define CCLASS_H
 
 
class pAClass;
class CClass
{
    public:
        CClass(pAClass* _AClass_);
        virtual ~CClass();
    protected:
    private:
        pAClass* _aClass;
};
 
#endif // CCLASS_H
 
 

CClass.cpp
cpp

#include "AClass.h"
 
CClass::CClass(pAClass* _AClass_)
:_aClass(_AClass_)
{
//  this->_aClass = _AClass_; /\ UP /\
   AClass* myClass = static_cast<AClass>(this->_aClass);
   myClass->getBClass()->testFunction();
}
 
CClass::~CClass()
{
    //dtor
}


To oczywiście przykład kodu zmodyfikowany na potrzeby metody "po Twojemu" :)
Moja wiedza na temat C++ nie jest wielka więc miło będzie się czegoś dowiedzieć

Pozdrawiam.

#6 Kaczus

    Bywalec

  • Użytkownicy
  • 36 Postów:

Napisano czw, 17 mar 2016 - 11:15

A co to za twór
cpp
class pAClass;


Dodatkowo trochę zbyt chojnie wstawiasz średniki :)

#7 spike

    Pomocna dłoń

  • Super użytkownicy
  • 181 Postów:

Napisano czw, 17 mar 2016 - 16:13

Z poprzednich Twoich wypowiedzi napisałeś:
cpp

class A;
class C
{
...
 


więc to jest zamiast "class A;"
Sam to zaproponowałeś.
Ps. średniki są na zakończenie instrukcji, co w tym złego? I proszę napisz gdzie widzisz nadmiar średników ?

#8 Kaczus

    Bywalec

  • Użytkownicy
  • 36 Postów:

Napisano czw, 17 mar 2016 - 16:53

Tak napisałem i tak ma być, to było class A, do twojego class A - ma dokładnie tak samo się nazywać! Czyli w przypadku opisanym w drugim przykładzie, co dałes ma być class AClass;

#9 spike

    Pomocna dłoń

  • Super użytkownicy
  • 181 Postów:

Napisano czw, 17 mar 2016 - 17:42

A to wybacz proszę :]
Tak działa wszystko tak jak powinno, wystarczyło wspomnieć, że to ma być prototyp.
A o prototypach w C++ zapomniałem.
A średniki nie zauważyłem przy pisaniu, w pliku AClass.cpp jest nadmiar przy metodach getBClass() i getCClass().
Kod na szybko pisany.




Dzięki za pomoc.
Pozdrawiam.