Wskaźnik do składowej klasy będącej tablicą

Odpowiedz Nowy wątek
2010-07-08 17:45

Rejestracja: 11 lat temu

Ostatnio: 8 lat temu

0

Weźmy taki prosty program:

class A
{   public:
        int n;
        int tab[10];
};

int main()
{   int A::*wsk1 = &A::n;
    //int A::*wsk2 = A::tab;
    return 0;
}

To kompiluje się bezproblemowo, ale odkomentowanie linii

    //int A::*wsk2 = A::tab;

powoduje błąd kompilacji. Z tego co wiem powinno się dać pokazywać na tę tablicę, czy mógłby ktoś podpowiedzieć jak?

Pozostało 580 znaków

2010-07-08 18:02
Moderator

Rejestracja: 16 lat temu

Ostatnio: 5 godzin temu

0

int A::*wsk2 to znaczy:
wsk2 jest wskaźnikiem do pokazywania wewnątrz klasy A na obiektu typu int
A ty przecież chcesz pokazać na tablicę a nie na jednego inta. Po prostu źle ten wskaźnik napisałeś.


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2010-07-25 09:23

Rejestracja: 13 lat temu

Ostatnio: 1 rok temu

0

przemyśl swoja odpowiedz jeszcze raz, Shalom. Blad autora tkwi tylko w tym, ze przy A::tab zapomnial &

zarowno:
int A::wsk2 = &A::tab; //edit <------------- FAIL, ta linia jest nieprawidlowa (czemu? czytaj dalej)
int (A::
wsk2)[10] = &A::tab;
sa poprawne i roznia sie tylko tym, czy z punktu widzenia wskaznika tablica jest sztywnoelementowa czy nie.


no to pojechałem z nieobecnością.. chwila przerwy i prawie rok przeleciał

Pozostało 580 znaków

2010-07-25 10:19
Moderator

Rejestracja: 16 lat temu

Ostatnio: 5 godzin temu

0

@quetzalcoatl masz rację (choć nie do końca, o czym dalej), ale uważam że ja pośrednio też ją mam. Ja tylko przeczytałem ten wskaźnik. Poza tym nadal uważam że jest on źle napisany. Wersja:

int (A::*wsk)[10] = &A::tab;

czyli: wsk jest wskaźnikiem do pokazywania wewnątrz klasy A na obiekty typu 10-elementowa tablica intów
jest moim zdaniem tą poprawną.
Taka wersja "int A::*wsk2 = &A::tab;" ci się w ogóle kompiluje? Ta wersja jest lekko nielogiczna, bo jakiego typu jest tutaj w takim razie "tab"?

Rozłóżmy to na czynniki pierwsze (bo może ja zwyczajnie coś przeoczyłem :) )
int A::*wsk2 = &A::tab
po lewej mamy wskaźnik, po prawej stronie pobieramy adres który przekazujemy temu wskaźnikowi
po lewej mamy wskaźnik na inta, wiec po prawej powinniśmy pobrać adres inta
z tego wynika że "tab" musiałoby być intem, a nie jest, bo jest tablicą intów, ew można by uznać że to wskaźnik do inta.
Konkludując jeśli w ogóle to musiałoby to być:

int* A::*wsk;

Ale g++ też pozwoli na przypisanie temu wskaźnikowi adresu tablicy o statycznym rozmiarze.

Brak ampersanda to raczej przeoczenie autora jak i moje, bo oczywiście jak mamy wskaźnik to trzeba mu podać jakis adres.

Oczywiście zdaje sobie sprawę z tego ze skillem w C/C++ zjadasz mnie na śniadanie ;) Więc zakładam taką możliwość że zwyczajnie zjadłeś tam tą jedną gwiazdkę ;)


Masz problem? Pisz na forum, nie do mnie. Nie masz problemów? Kup komputer...

Pozostało 580 znaków

2010-07-25 13:07

Rejestracja: 14 lat temu

Ostatnio: 1 rok temu

0

Hallo @all!

A. Operator "::" jest to tzw. "Scope Resolution Operator" ktory umozliwia dostep do zmiennych o tej samej nazwie wystepujacych na roznych poziomach programu (patrz przyklad).

Nie rozumiem deklaracji zmiennych wsk1 i wsk2. Dlatego prosze o wyjasnienie ich sensu.

int main()
{        int A::*wsk1 = &A::n;
        //int A::*wsk2 = A::tab;
        return 0;
}

B. Na moj chlopski rozumek, aby wyjasnic sprawe wskaznikow w klasie A, powinno sie stworzyc obiekt takiej klasy:

#include "stdafx.h"
#include <iostream>
using namespace std;

class A
{
    public:
                int n;
                int tab[10];
};

int _tmain(int argc, _TCHAR* argv[])
{
    A *ObjektA = new A();

    ObjektA->n = 15;
    ObjektA->tab[0] = 27;

    int  *wsk1 = &ObjektA->n;
    int  *wsk2 = ObjektA->tab;

    cout << &ObjektA->n   << "   " << ObjektA->n << "\n";
    cout << wsk1 << "   " << *wsk1 << "\n";

    cout << ObjektA->tab  << "   " << ObjektA->tab[0] << "\n";  
    cout << wsk2 << "   " << *wsk2 << "\n";

    system("Pause");

    return 0;
}

Czy moze zupelnie czegos nie zrozumialem?

Pozdrawiam
Markus


Go Hard Or Go Home

Pozostało 580 znaków

2010-07-27 14:09

Rejestracja: 13 lat temu

Ostatnio: 1 rok temu

0

Shalom: przynam sie od razu, ani mojej linijki #1 ani linijka #2 nie sprawdzilem, tylko napisalem jak leci. Teraz defacto troche mi sie tez nie chce, ale skoro jest watpliwosc to sprawdzilem - tylko druga jest uznawana za poprawna przez mscv2008. Błąd przy tej która Tobie nie pasuje wynika nie z powodu skladni, ale z powodu niedozwolonej kowersji typow, ktora przy member-pointerach jest bardziej restrykcyjna.

struct X{ int ar[10]; };

int main()
{
    //int (X::* ptr) = &X::ar;      // moj fail - niemozliwe
    int (X::* ptr2)[10] = &X::ar;

    X a;
    int (* ptr3) = a.ar;            // autokonwersja int[] -> int*
    int (* ptr4)[10] = &a.ar;
}

piszac na szybko, zasugerowalem sie przypadkiem 'ptr3'. masz racje, ze w tym przypadku musialoby to wygladac jak intX:: -- ale w tylko w przypadku tablicy dynamicznej! int[10] zawarta w X jest statyczna, wiec co najwyzej moj zapis mogl byc poprawny. nie jest - gdyz nie mozna membera int[10] potraktowac jako serii memberow typu int ---- a moj zapis to dokladnie by oznaczal


no to pojechałem z nieobecnością.. chwila przerwy i prawie rok przeleciał

Pozostało 580 znaków

2010-07-27 14:44

Rejestracja: 12 lat temu

Ostatnio: 6 godzin temu

0

Wszystko pięknie, ale autorowi wątku chodzi raczej o to by mieć wskaźnik do int wewnątrz klasy A, który wskazuje na element tablicy będącej wewnątrz tej klasy.
Czyli autor nie ma problemu z lewą częścią wyrażenia (jak poprawia quetzalcoatl), ale z prawą, bo może chcieć wskaźnika na 3 element tej tablicy a nie na 0.
Na gcc próbowałem static_cast i nie zadziałało (inne rzutowania byłyby jak strasznie topornym rozwiązaniem).


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

Pozostało 580 znaków

2010-07-27 15:04

Rejestracja: 13 lat temu

Ostatnio: 1 rok temu

0

@MarkusB/pytanie A
:: dokladnie tak sie nazywa, ale uzywa sie go w wielu roznych miejscach.
jedno z nich to "chodzenie" po namespaceach,
inne, to "chodzenie" po skladnikach klasy

namespace A
{
  namespace B
  {
    int zmienna;
    class C
    {
      int pole;
      class D { int pole2; };
    };
  }
}

pelna nazwa zmiennej globalnej: A::B::zmienna
pelna nazwa pola klasy: A::B::C::pole
pelna nazwa pola innerklasy: A::B::C::D::pole

jezeli teraz chcesz w dowolnym miejscu kodu powiedziec, niech zmienna globalna wynosi 5, zapiszesz to:

A::B::zmienna = 5;
B::zmienna = 5;
zmienna = 5;

w zaleznosci w ktorym miejscu aktualnie "się" znajdujesz względem struktury namespaceow.

podobnie, jezeli "jestes" poza klasa, jakos musisz wskazac że chodzi Ci po 'pole' z klasy C a nie D, zapisy:

&C::pole
&D::pole

powinny więc być dla Ciebie w miare oczywiste

teraz, "luźnolatający" wskaznik na int, to jest po prostu int*
wskaznik na cos-w-klasie nie jest "luźnolatający", poniewaz aby go uzyc musisz podac instancje klasy. obiekt:

int a = 5;
int b = 5;

int* wskaznik = &a;
.....
int cede = *wskanzik; //odczyta zawartosc 'a', nie 'b'
class Klasa{int POLE, POLEINNE;};

Klasa a = .....;
Klasa b = .....;

???? wskaznik = &Klasa::POLEINNE; // ustawiamy wskaznik na pole 'POLEINNE' klasy.
.....
//cede = *wskaznik; -- nie mozna! z czego mial by ten wskaznik odczytac? z obiektu A czy obiektu B?

cede = a .* wskaznik;   //bierzemy obiekt, a potem na nim wywolujemy wskanzik-na-pole. odczyta zawartosc z 'a', nie 'b'

jak sie zastanowic, roznica uzycia wskaznika-na-zawartosc oraz zwyklego wskaznika robi sie w miare sensowna. specjalnie w kodzie powyzej napisalem ????? zamiast typu wskaznika. roznica w nich oznacza, ze ????? to nie jest int*. jak wiec zapisac ze wskaznik ma byc na-int, ale ze dodatkowo ma byc na-cos-w-klasie-Klasa?

odpowiedz brzmi: do definicji wskaznika trzeba dolaczyc operator zakresu, ::

Co WCzym:: zmienna; kontra Co zmienna;

z namespaceow pamietasz pewnie, ze "topowy" namespace to puste ::, tutaj tez to NIE funkcjonuje, ale mozesz tak na to patrzec:

Co WCzym:: zmienna; kontra Co :: zmienna;

prawa wersja mowi, ze wskazywane "co" jest na samej gorze, nie jest opakowane
lewa wersja mowi, ze "Co" ma byc opakowane przez WCzym

specjalny zapis " WCzym::* " to wskaznik-w-opakowanie.
z namespaceami:

int (A::B::C::D::* zmienna) = &A::B::C::D::pole ---- adres pola w klasie D w klasie C w namespace A::B

niestety, skladnia C++ jest jesli chodzi o wskazniki totalnie kontra-intuicyjna. tak samo jak zapis wskaznikow na zlozone tablice czy funkcje jest wrogi, tak tutaj jest tylko troszke lzej.. moze i pieknie by bylo, gdybysmy kiedys mogli napisac: A::B::C::D::int* zmienna = &A::B::C::D::pole;

... ale wtedy skad kompilator by wiedzial, ze chodzi o TEN int, a nie o nasza klase ktora siedzi w A::B::C::D:: i nazywa sie 'int'? nie daloby sie. kolejna proponowalna 'lepsza' skladnia to np. A::B::C::D::(std::int)* zmienna = &A::B::C::D::pole; ale szczerze, ja juz przywyklem do obecnej i juz mnie malo rzeczy razi (jak sobie rozważę alternatywy:) )


no to pojechałem z nieobecnością.. chwila przerwy i prawie rok przeleciał

Pozostało 580 znaków

2010-07-27 15:08

Rejestracja: 13 lat temu

Ostatnio: 1 rok temu

0
MarekR22 napisał(a)

Wszystko pięknie, ale autorowi wątku chodzi raczej o to by mieć wskaźnik do int wewnątrz klasy A, który wskazuje na element tablicy będącej wewnątrz tej klasy.
Czyli autor nie ma problemu z lewą częścią wyrażenia (jak poprawia quetzalcoatl), ale z prawą, bo może chcieć wskaźnika na 3 element tej tablicy a nie na 0.
Na gcc próbowałem static_cast i nie zadziałało (inne rzutowania byłyby jak strasznie topornym rozwiązaniem).

autor wątku powiedzial:

Z tego co wiem powinno się dać pokazywać na tę tablicę, czy mógłby ktoś podpowiedzieć jak
wiec dostał odpowiedzi takie.. zapytalby o pokazywanie na jej zawartosc, dostalby inne.

pokazywać na n-ty element tablicy mozna, a jakze - przez zwykly int*, tylko trzeba miec instancje obiektu

class Klasa{int tab[10];}

Klasa x;
int * ptr = &x.tab;
*(ptr+4) = 666;

Mowienie o wskazniku na element tablicy luznolatajacej, a o wskazniku na element tablicy nalezacej do obiektu klasy, nie rozni sie absolutnie niczym.

tyci trick w tym, ze:

  • jesli mowimy o tablicy - mowimy o wnetrzy obiektu lub wnetrzu klasy
  • jesli mowa o elemencie tablicy to mowimy juz o wnetrzu istniejacego obiektu klasy

Tak jak napisalem w poscie do Shaloma:

  • majac luznolatajaca tablice Elem[], z racji C i temu podobnych, mozna traktowac jej elementy osobno jako osobne byty i brac do nich Elem*, autokonwersja ptr istnieje
  • nieluznolatajace, pole int klasy oraz element int pola tablicowego klasy nie sa rownoznaczne. nieistnieje autokonwersja (&X::Elem[])+i -> X::Elem. w przeciwienstwie do int, zapis X::int* oznacza membera klasy. element i-ty tablicy bedacej memberem klasy nie jest memberem klasy. jak widziales w moim pierwszym poscie, tez mnie to zdziwilo. pewnie niedopatrzenie, albo wzgledy alignu..

prosty "dowód" tego o czym mowie:

struct Y{ int a,b,c; int d[10]; };

Y y;
int Y::* p = &Y::a;

y.*p = 1;
++p;            // co to mialoby byc? przejscie na 'B' ?? obiekt to nie tablica. jesli chcemy grzebac w nim na zywca, to nie przez member pointer, tylko raw pointer..
y.*p = 2;

dlatego wlasnie elementow Y::d nie da sie uzywac jako "int Y::" --- bo mimo podobienstwa zapisu, to nie to samo. elementy tablicy D to int


no to pojechałem z nieobecnością.. chwila przerwy i prawie rok przeleciał

Pozostało 580 znaków

Odpowiedz

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