Konwersja klasy.

0

Witam, uczę się z Symfonii C++ i jestem na rozdziale dotyczącym konwersji między klasami i napotkałem pewien problem. Oto przykład z książki:

#include <iostream>
#include <string>
using namespace std;

class numer;

class zespol
{
private:
	float rzeczyw;
	float urojon;
public:
	zespol(float r = 0, float u = 0) : rzeczyw(r), urojon(u){}
	zespol(numer);
};

class numer
{
	float n;
	char opis[80];
	friend zespol::zespol(numer);
public:
	numer(int k, char *t = "bez opisu") : n(k)
	{
		strcpy(opis,t);
	}
};

zespol::zespol(numer ob)
{
	rzeczyw = 0b.n;
	urojon = 0;
}

zespol dodaj(zespol a, zespol b)
{
	zespol suma(0, 0);
	suma.rzeczyw = a.rzeczyw + b.rzeczyw;
	suma.urojon = a.urojon + b.urojon;
	return suma;
}

int main(void)
{
	cin.get();
	cin.get();
	return 0;
}

Kompilator podświetla mi następujące fragmenty kodu:

class numer
{
	float n;
	char opis[80];
	friend zespol::zespol(numer);
public:
	numer(int k, char *t = "bez opisu") : n(k)
	{
		strcpy(opis,t);
	}
};

W linijce

friend zespol::zespol(numer)

podkreśla zespol(numer);

 i po najechaniu na zespol pisze:
no instance for overloaded function zespol::zespol matches the specified type. a po najechaniu na numer: copy constructor for class "numer" may not have parameter of type numer.

Czemu konstruktor nie może mieć parametru tego typu? Przecież tak jest pokazane w książce.

```cpp
zespol::zespol(numer ob)
{
	rzeczyw = ob.n;
	urojon = 0;
}

W tym fragmencie podkreśla n i pisze, że: member numer::n is inaccessible
O ile tutaj rozumiem czemu jest niedostępny, ponieważ jest zadeklarowany jako prywatny i po zmianie na public nie podkreśla już. Ale przecież w linijce

friend zespol::zespol(numer);

klasa numer pozwala aby konstruktor klasy zespol miał dostęp do jej składników prywatnych. Czyżby autor się pomylił?

Autor też dodaje, że funkcja odpowiedzialna za dodawanie liczb zespolonych jest identyczna jak w poprzednich przykładach, czyli:

zespol dodaj(zespol a, zespol b)
{
	zespol suma(0, 0);
	suma.rzeczyw = a.rzeczyw + b.rzeczyw;
	suma.urojon = a.urojon + b.urojon;
	return suma;
}

Lecz i tutaj podkreśla mi fragmenty z rzeczyw i urojon i występuje podobnym problem z dostępem jak wyżej i pomaga dodanie public przed tym fragmentem:

class zespol
{
	float rzeczyw;
	float urojon;

Kolejna pomyłka autora? Te dwa ostatnie problemy nie są tak uciążliwe gdyż wiem jak je rozwiązać bardziej zależy mi na tym pierwszym dotyczącym konwersji klas. Czemu to nie działa?

0

za długi ten post do czytania, ale ten konstruktor jak deklarujesz tak:
zespol(float r = 0, float u = 0)
to jak dodajesz go jako przyjaciela to powinieneś dodać go tak samo:
zespol::zespol(float r, float u)

0
krwq napisał(a)

za długi ten post do czytania, ale ten konstruktor jak deklarujesz tak:
zespol(float r = 0, float u = 0)
to jak dodajesz go jako przyjaciela to powinieneś dodać go tak samo:
zespol::zespol(float r, float u)

Ale ja nie mam problemu z tym konstruktorem. Tylko z tym:

zespol(numer);

Numer to inna klasa.

1

Nic nie rozumiem z twojego bełkotu. Naucz się moze pisać po polsku zanim zaczniesz uczyć się programowania. Kod który podałeś jest prawie poprawny...

#include <iostream>
#include <cstring>
using namespace std;

class numer;

class zespol
{
private:
    float rzeczyw;
    float urojon;
public:
    zespol(float r = 0, float u = 0) : rzeczyw(r), urojon(u) {}
    zespol(numer);
    friend zespol dodaj(zespol a, zespol b); //bo jak inaczej funkcja dodaj() ma miec dostep do pol prywatnych klasy zespol?
};

class numer
{
    float n;
    char opis[80];
public:
    numer(int k, const char *t = "bez opisu") : n(k)
    {
        strcpy(opis,t);
    }
};

zespol::zespol(numer ob)
{
    rzeczyw = ob.n;
    urojon = 0;
}

zespol dodaj(zespol a, zespol b)
{
    zespol suma(0, 0);
    suma.rzeczyw = a.rzeczyw + b.rzeczyw;
    suma.urojon = a.urojon + b.urojon;
    return suma;
}

int main(void)
{
    cin.get();
    cin.get();
    numer x(1);
    dodaj(zespol(x),zespol(1,2));
    return 0;
}

Poza tym nie rozumiesz o co chodzi w deklaracji przyjaźni...

0

No dobra, wszystko prawie ok. Jak widzę usunąłeś

class numer
{
    float n;
    char opis[80];
public:
    numer(int k, const char *t = "bez opisu") : n(k)
    {
        strcpy(opis,t);
    }
};

z tego fragmentu kodu linijkę:

friend zespol::zespol(numer);

i przez to trzeba dać zmienną n do publicznych, aby konstruktor miał do niej dostęp.
Ale załóżmy, że ja chce aby zmienna n była private tak jak w książce. Chodzi mi po prostu o to jak dodać do klasy numer konstruktor klasy zespol jako przyjaciela, ponieważ jak pisałem przykład z książki podkreśla mi takową deklaracje:

friend zespol::zespol(numer);

Jak w takim razie taka deklaracja powinna wyglądać.

0

Jak już mówiłem, NIE ROZUMIESZ o co chodzi w przyjaźni. Nie możesz z poziomu klasy numer dodać sobie przyjaciela z klasy zespol, bo jaki by to miało sens? o_O Tylko klasa zespol może deklarować swoich przyjaciół. Zresztą nadal nie rozumiem o co ci chodzi, bo konstruktor zespol(numer) jest publiczny więc każdy może go wywołać i żadna przyjaźń nie jest konieczna. Pole 'n' klasy numer nie musi być publiczne bo obiekt klasy numer ma dostęp do wszystkich swoich pól, a jak przekażesz wartość tego pola jako argument metody to klasa zespol też będzie miała do tego argumentu dostęp (w zasadzie to do jego kopii!)

0

Trochę odkopuję, ale miałem ten sam problem, jak ktoś będzie przerabiał Symfonię może mieć to samo.

olek1 napisał(a):

No dobra, wszystko prawie ok. Jak widzę usunąłeś (...) z tego fragmentu kodu linijkę:
friend zespol::zespol(numer);
i przez to trzeba dać zmienną n do publicznych, aby konstruktor miał do niej dostęp.
Ale załóżmy, że ja chce aby zmienna n była private tak jak w książce. (...)Chodzi mi po prostu o to jak dodać do klasy numer konstruktor klasy zespol jako przyjaciela, ponieważ jak pisałem przykład z książki podkreśla mi takową deklaracje(...)

Polecam powyższym Panom czytanie ze zrozumieniem.
Nie jest to do końca jasno napisane, jednak to konstruktor klasy zespol ma mieć dostęp do zmiennych prywatnych klasy numer. Nie konstruktor tej samej klasy -_-

Mniej zawile:
Chcemy, aby:

  1. konstruktor klasy A
  2. przyjmujący jako argument obiekt klasy B, czyli A::A(B)
  3. miał dostęp do zmiennych prywatnych klasy B

Trzeba więc w klasie B zadeklarować przyjaźń dla tego konstruktora.
Czyli w ciele klasy B:
friend A::A(B);

Visual wypluwa błędy widoczne wyżej.

 
#include <iostream>
#include <conio.h>
using namespace std;

class B;

class A
{
public:
	A(B);
};

class B
{
	int b;
public:	
	B(int n):b(n){};

	friend A::A(B);
};

A::A(B obj)
{
	cout << obj.b;
}

int main()
{
	A objA(B(2));

	getch();
	return 0;
}

W Visualu 2012 Express wyrzuca błędy - tak jakby interpretował deklarację przyjaźni jako konstruktor kopiujący. Mimo wszystko kompiluje się i zgodnie z domysłem na ekranie pojawia się 2. Nie jestem znawcą, jak na moje to jakiś bug i tyle.

PS:

Shalom napisał(a):

Jak już mówiłem, NIE ROZUMIESZ o co chodzi w przyjaźni. Nie możesz z poziomu klasy numer dodać sobie przyjaciela z klasy zespol, bo jaki by to miało sens? o_O

Może. Jaki miałoby to sens? Dzięki temu wybrana funkcja klasy zespół miałaby dostęp do 3 zmiennych prywatnych klasy numer.

Shalom napisał(a):

Tylko klasa zespol może deklarować swoich przyjaciół. Zresztą nadal nie rozumiem o co ci chodzi, bo konstruktor zespol(numer) jest publiczny więc każdy może go wywołać i żadna przyjaźń nie jest konieczna.

A co ma przyjaźń do wywoływania danego konstruktora? Tu chodzi o to, aby konstruktor miał dostęp do prywatnych składników klasy która deklaruje swoją przyjaźń z tym konstruktorem. Po tym zdaniu wnoszę, że nie rozumiesz idei przyjaźni lub kompletnie nie zrozumiałeś problemu, sądząc po poprawionym kodzie - pewnie to drugie. Jak widać łatwo rzuca się oskarżeniami.

Faktem jest, ze funkcja dodaj z jakiegos powodu byla niezaprzyjazniona, to tez powodowalo bledy, ale nie o to chodzilo w tym temacie.

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