Dlaczego nie działa kod z kompozycją ?

0
#include <iostream>

class Punkt
{
    int x,y;
    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};
class Linia
{
    Punkt p1,p2;
    Linia(Punkt a, Punkt b)
    {
        p1 = a;
        p2 = b;
    }
};

int main()
{
    Punkt x(4,4), y(2,2);
        Linia(x,y);
        return 0;
}
 
1
#include <iostream>
 
class Punkt
{
    	int x,y;
    public: 
	    Punkt(int xx, int yy)
	    {
	        x = xx;
	        y = yy;
	    }
};
class Linia
{
    	Punkt p1,p2;
    public:
	    Linia(Punkt a, Punkt b):p1(a),p2(b)
	    {
	    }
};
 
int main()
{
    Punkt x(4,4), y(2,2);
    Linia(x,y);
    return 0;
}

Czemu?

  1. Konstruktory miałeś prywatne więc nic byś nie stworzył
  2. W ciele konstruktora wszystkie pola muszą już być utworzone, więc wołane są bezargumentowe konstruktory pól klasy. U ciebie dla klasy Punkt takiego nie ma więc Linia nie mogła utworzyć tego pustego obiektu.
0

To tylko na liście inicjalizacyjnej można to zrobić ?

Nie mogę zrozumieć czemu nie mogę w ciele konstruktora tego zrobić co w liście inicjalizującej zrobiłeś.

1

Bo jeśli zadeklarowałeś jakis konstruktor to NIE zostanie wygenerowany automatycznie konstruktor bezargumentowy. Ale konstruktor kopiujący zgodny z ideą "pole po polu" będzie. W twoim kodzie brakowało konstruktora bezargumentowego bo w ciele konstruktora Linia wszystkie pola klasy muszą już być utworzone. Tzn zanim dojdziesz do twojego p1=a to obiekt p1 musi istnieć. A u ciebie nie da sie go stworzyć.

0

Z konstruktorem bezargumentowym też nie działa:

#include <iostream>

class Punkt
{
    int x,y;
    public:
    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};
class Linia
{
    Punkt p1,p2;
    public:
    Linia()
    {
        p1 = a(4,8);
        p2 = b(10,11);
    }
};

int main()
{
    Punkt x(4,4), y(2,2);
        Linia();
        return 0;
}
0

Miał być obiekt dynamiczny, lecz nadal nie działa:

 #include <iostream>

class Punkt
{
    int x,y;
    public:
    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};
class Linia
{
    Punkt p1,p2;
    public:
    Linia()
    {
        Punkt p1 = new a(4,8);
        Punkt p2 = new b(10,11);
    }
};

int main()
{
    Punkt x(4,4), y(2,2);
        Linia();
        return 0;
}
0

a oraz b zamien na Punkt i zadziala. Poza tym pamietaj o tym żeby zniszczyć te obiekty w destruktorze.

1

Teraz to w ogóle bez sensu zrobiłeś bo polami klasy są nadal obiekty a potem je przesłaniasz lokalnymi zmiennymi... Zrób
Punkt *p1,*p2; a w konstruktorze już samo p1 = new Punkt(4,8);. C++ to nie java...

0

Działa, tylko się nie mogę dojść jak to zrobić na zwykłych obiektach automatycznych bez listy inicjalizacyjnej?

#include <iostream>

class Punkt
{
    int x,y;
    public:
    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};
class Linia
{
    Punkt *p1,*p2;
    public:
    Linia()
    {
        Punkt *p1 = new Punkt(4,8);
        Punkt *p2 = new Punkt(10,11);
    }
};

int main()
{
        Linia();
        return 0;
}
 
0

przytoczę Ci najważniejszy fragment z wypowiedzi Shaloma, a kluczowe słowa pogrubię:

W ciele konstruktora wszystkie pola muszą już być utworzone (...).

W klasie masz pola Punkt p1, p2, a jeśli podczas ich tworzenia na liście inicjalizacyjnej sam jawnie nie wywołasz konstruktora dla tych obiektów Punkt(int, int) to zostanie wywołany konstruktor bezargumentowy, którego nie zdefiniowałeś (kompilator nie zrobi tego za Ciebie). W ciele konstruktora posługujesz się już utworzonymi obiektami.

0

Kod jest zły bo przeslaniasz pola klasy zmiennymi lokalnymi. Czego jesscze nie rozumiesz? Napisz w klasie punkt konstruktor bezargumentowy i będzie ci działać bez listy inicjalizacyjnej.

0

Działa:

#include <iostream>

class Punkt
{
    int x,y;
    public:
    Punkt()
    {
        x = 4;
        y = 10;
    }
    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};
class Linia
{
    Punkt p1,p2;
    public:
    Linia(Punkt a, Punkt b)
    {
        Punkt p1 = a;
        Punkt p2 = b;
    }
};

int main()
{
    Punkt x(10,10), y(20,20);

        Linia(x,y);
        return 0;
}
 

Ale jednak nadal nie rozumiem dlaczego bez konstruktora bezparametrowego to nie działa, jak przecież w mainie tworzę punkty o określonych współrzędnych, a potem je chce przekazać do konstruktora klasy Linia.

0

Nie mogę zrozumieć czemu nie mogę w ciele konstruktora tego zrobić co w liście inicjalizującej zrobiłeś.

Bo nie. Jeśli w klasie masz pole Punkt p1; i nie inicjalizujesz tego pola na liście inicjalizacyjnej, to znaczy że inicjalizujesz to pole konstruktorem bezparametrowym. Więc musi on wtedy być.

Ciało konstruktora jest odpalane dopiero gdy pola klasy są zainicjalizowane.

0

no nie do końca to dobrze zrobiłeś:

Punkt p1, p2;
public:
Linia(Punkt a, Punkt b)
{
	Punkt p1 = a;
	Punkt p2 = b;
}

w ciele konstruktora tworzysz dwa lokalne obiekty p1, p2 (przysłaniające pola klasy p1, p2) i przypisałeś im przekazane a i b, gdy zaraz po jego wykonaniu oba obiekty zostaną zniszczone. Czy ma to Twoim zdaniem jakikolwiek sens?

(...) dlaczego bez konstruktora bezparametrowego to nie działa, przecież w mainie tworzę punkty o określonych współrzędnych, a potem je chce przekazać do konstruktora klasy Linia.

tam nie leżał problem. Dla obiektów lokalnych w main wywoływałeś konstruktor Punkt(int, int) więc nie było problemów. Następnie przekazywałeś je do konstruktora Linia(Punkt, Punkt). W tym konstruktorze był problem z utworzeniem pól Punkt tej klasy, który już wcześniej został opisany.

Poważnie, przeczytaj ze zrozumieniem kilka razy ten wątek, bo już wszystko zostało powiedziane.

0

Może tak, po kolei na spokojnie:

#include <iostream>
using namespace std; 

class Punkt
{
    int x,y;
public:
    Punkt(int xx, int yy) : x(xx), y(yy){ }
	int getX(){ return x; }
	int getY(){ return y; }
};

class Linia
{
    Punkt p1, p2;
public:
    Linia(int aa, int ab, int ba, int bb) : p1(aa, ab), p2(ba, bb){ }
	void wypisz(){ cout << p1.getX() << " " << p1.getY() << endl << p2.getX() << " " << p2.getY() << endl; }
};
 
int main()
{
	Linia(4, 3, 1, 4).wypisz();
    return 0;
}

W klasie Linia obiekty p1 oraz p2 to nie są wskaźniki w tylko już "pełnoprawne" obiekty. Nie możesz na nich wywoływać operatora new, tak jak to się robi w C# chociażby, ponieważ to jest to samo co int x, y w klasie Punkt :) Tam nie używasz new w stosunku do intów, a mógłbyś jeżeli byłoby wskaźnikami, więc w klasie Linia nie używaj ich w stosunku do Punków.

https://ideone.com/oREH3t

Poza tym, w twoim pierwotnym kodzie, utworzyłeś konstruktory prywatne. Prywatny konstruktor danej specjalizacji uniemożliwia utworzenie wg niej obiektu.

Twoja pierwotna klasa nie działała, bo powinno to wyglądać tak:

#include <iostream>
using namespace std;
 
class Punkt
{
    int x,y;
public:
    Punkt(int xx, int yy) : x(xx), y(yy){}
};
class Linia
{
    Punkt p1,p2;
public:
    Linia(Punkt a, Punkt b) : p1(a), p2(b){} // Użycie listy inicjalizacyjnej zamiast operatora przypisania w ciele ctor'a
};
 
int main()
{
    Punkt x(4,4), y(2,2);
    Linia(x,y);
    return 0;
}

PS: Ja wiem, że C# np. by to przepuścił, bo tam obiekty p1 i p2 to tak naprawdę obiekty typu referencyjnego czyli takie, które przechowują adresy. Takie wskaźniki.

0

A to nie ma być tak???

#include <iostream>
using namespace std;

class Punkt
{
public:
    int x,y;

    Punkt(int xx, int yy)
    {
        x = xx;
        y = yy;
    }
};

class Linia
{
public:
    Punkt *p1, *p2;

    Linia(Punkt *a, Punkt *b)
    {
        p1 = a;
        p2 = b;
    }
};

int main()
{
    Punkt *x = new Punkt(4, 4), *y = new Punkt(2, 2);
    Linia *ln = new Linia(x, y);

    cout << "Punkt P1:\n\n";
    cout << "X = " << ln->p1->x << " Y = " << ln->p1->y << "\n\n";
    cout << "Punkt P2:\n\n";
    cout << "X = " << ln->p2->x << " Y = " << ln->p2->y;

    delete ln;
    delete x;
    delete y;

    return 0;
}

Pola publiczne dałem celowo tylko żeby sprawdzić.

0

Niepotrzebnie sobie komplikujesz życie. Po pierwsze masz tam publiczne składowe ale dostęp to i tak jest zależny od tego co chcesz z nimi robić. Po drugie po co używasz wskaźników jak możesz referencji:

#include <iostream>
using namespace std;
 
class Punkt
{
public:
    int x,y;
 
	Punkt(int xx, int yy) : x(xx), y(yy){}
};
 
class Linia
{
public:
    Punkt p1, p2; 
	Linia(const Punkt& a, const Punkt& b) : p1(a), p2(b){}
};
 
int main()
{
    Punkt p1(4, 4);
	Punkt p2(2, 2);
    Linia ln(p1, p2);
 
    cout << "Punkt P1:\n\n";
    cout << "X = " << ln.p1.x << " Y = " << ln.p1.y << "\n\n";
    cout << "Punkt P2:\n\n";
    cout << "X = " << ln.p2.x << " Y = " << ln.p2.y;
 
    return 0;
}

I ostatnie: C++ to nie Java czy C#, a widzę że usilnie chcesz używać new i tworzyć obiekty tak jak w językach zarządzanych.

0

Próbowałem teraz w c# napisać i nie wiem czemu nie działa mi wypis na ekran przez System.out.print

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;

class Punkt
{
    public int x, y;
    public Punkt(int xx, int yy) { x = xx; y = yy; }

}
class Linia
{
    private Punkt p1, p2;

    public Linia(Punkt a, Punkt b)
    {
        p1 = a;
        p2 = b;
    }
    public void przesun(int dx, int dy)
    {
        p1.x += dx; p1.y += dy; p2.x += dx; p2.y += dy;
    }
    public String toString()
    {
        return "(" + p1.x + "," + p1.y + ")->(" + p2.x + "," + p2.y + ")";
    }
}

namespace po2
{
    class Program
    {
        static void Main(string[] args)
        {
            Punkt pierwszy = new Punkt(0, 0);
            Punkt drugi = new Punkt(1, 1);
            Linia l1 = new Linia(pierwszy, drugi);
            Linia l2 = new Linia(pierwszy, drugi);
            System.out.print(l2.toString());

        }
    }
}
 
0

Ty coś bierzesz? Lepiej odstaw... C# nie ma żadnego System.out.println. Ty piszesz te kody lodówką że ci IDE nie podpowiada że coś jest nie tak w kodzie? o_O Przecież to ci sie nawet nie kompiluje!

Console.WriteLine(l2.toString());
2
  1. Twoje sie nie kompiluje
    http://ideone.com/xyP4U3
  2. bo musisz to napisac w pythonie, tylko w pythonie to dziala
class Punkt:
	def __init__(self, x, y):
		self.x = x
		self.y = y

class Linia:
	def __init__(self, p1, p2):
		self.p1 = p1
		self.p2 = p2
		
p1 = Punkt(1,2)
p2 = Punkt(2,3)
l = Linia(p1,p2)

print(l.p1.x)
0

Czyli podsumowując, jeśli wykorzystuje w swoim kodzie kompozycję. To dla komponentów tworzyć zawsze konstruktor bezargumentowy ?

2

Nie. Musisz po prostu ROZUMIEĆ co robisz i co się dzieje w kodzie. A lista inicjalizacyjna zwykle jest tym czego potrzebujesz...

0

Chodzi i inicjalizację obiektów, z których chcesz korzystać. Jakoś tutaj nie masz domyślnych konstruktorów, a masz kompozycję i działa:

#include <iostream>
using namespace std;
 
class Punkt
{
public:
    int x,y; 
    Punkt(int xx, int yy) : x(xx), y(yy){}
};
 
class Linia
{
public:
    Punkt p1, p2; 
    Linia(const Punkt& a, const Punkt& b) : p1(a), p2(b){}
};
 
int main()
{
    Punkt p1(4, 4);
    Punkt p2(2, 2);
    Linia ln(p1, p2);
 
    cout << "Punkt P1:\n\n";
    cout << "X = " << ln.p1.x << " Y = " << ln.p1.y << "\n\n";
    cout << "Punkt P2:\n\n";
    cout << "X = " << ln.p2.x << " Y = " << ln.p2.y;
 
    return 0;
}

Słuchaj @Shalom'a i poczytaj o liście inicjalizacyjnej konstruktora.

5

Za nazywanie zmiennych: l, l1, l2 itd. należy ludzi bić i to bardzo mocno. Przecież to jest prawie nierozróżnialne od 1, 11 czy 12, i ma na celu chyba tylko wkurzenie czytających kod.

0
grzesiek51114 napisał(a):

Niepotrzebnie sobie komplikujesz życie. Po pierwsze masz tam publiczne składowe ale dostęp to i tak jest zależny od tego co chcesz z nimi robić. Po drugie po co używasz wskaźników jak możesz referencji:

I ostatnie: C++ to nie Java czy C#, a widzę że usilnie chcesz używać new i tworzyć obiekty tak jak w językach zarządzanych.

Ale ja tu nie widzę żadnego problemu :-) Po prostu zastosowałem wskaźniki i new oraz delete celem tworzenia tych klas dynamicznie. To tylko pod Arduino robiłem w ten sposób jak Ty piszesz. Dla mnie sposób w jaki to przedstawiłem to nie jest w zasadzie żadna komplikacja :-)

1

@drorat1 no i niedobrze ze nie widzisz problemu bo w C++ nie powinno uzywac golych new czy delete.
Od tego masz RAII (smart pointery)

0

Tzn. problem jest jak np. jakaś metoda klasy zgłosi wyjątek. Smart pointery rozwiązują ten problem?

0

;o? ze jak?

a niby jak new i delete rozwiaza ten problem?

jezeli jakas metoda rzuci wyjatek to musisz go zlapac. ani new ani delete ani smart pointery tego nie robia.

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