CRgn als Wert zurückgeben



  • Hallo!

    Ich habe eine Funktion geschrieben die mir einer CRgn Klasse als Wert zurückgibt.

    CRgn BorderRgn(CRgn &rgn)
    {
    CRgn MeineRegion;

    ...

    return MeineRegion;
    }

    aber es lässt sich nicht kompilieren,
    der Compiler meldet ...

    error C2558: class 'CRgn' : Kein Kopierkonstruktor verfuegbar

    Was soll ich tun ?

    Vielen Dank für Eure Hilfe.

    Gruß Ronny



  • gib die Region als Zeiger zurück, oder benutze HRGN



  • return *MeineRegion

    ???

    Ist das so korrekt ?

    und wie muss dann die Funktion deklariert sein ?

    Danke 🙂



  • Sagt der Standard nicht, dass es immer einen Copy-Konstruktor gibt? Und in den entsprechenden Headern ist er nicht explizit private oder protected deklariert...

    Wie auch immer. Wenn du einen Pointer zurückgeben willst, musst du das Objekt auf dem Heap anlegen, also:

    CRgn *BorderRgn(CRgn &rgn)
    {
      CRgn *MeineRegion = new CRgn();
    
      //... (MeineRegion ist jetzt ein Pointer, also alle member über -> ansprechen)
    
      return MeineRegion;
    }
    

    Allerdings musst du dann nachher höllisch aufpassen, dass du den Speicher wieder freigibst, außen rum müsste das also so aussehen:

    CRgn param, *border_reg;
    //... param createn usw.
    border_reg = BorderRgn(param);
    //... damit arbeiten
    delete border_reg;
    

    Sinnvoller wäre wohl:

    CRgn &BorderRgn(CRgn &rgn, CRgn &MeineRegion) 
    {
      //...
      return MeineRegion;
    }
    

    Das sieht zwar sehr nach C aus, hat aber den Vorteil, dass du keinen Speicher leckst. Der Aufruf sähe dann so aus:

    CRgn param, border_reg;
    //... param createn usw.
    BorderRgn(param, border_reg);
    //... damit arbeiten
    //nachher ist kein delete nötig
    

    Wenn du dir beide Möglichkeiten offen halten willst:

    CRgn *BorderRgn(CRgn &rg, CRgn *MeineRegion = NULL) 
    {
      if(MeineRegion = NULL) 
      {
        MeineRegion = new CRgn();
        //Createn usw.
      }
      //...
      return MeineRegion;
    }
    

    Dann sähe der Aufruf im zweiten Fall (wenn du delete vermeiden willst) allerdings so aus:

    BorderRgn(param, &border_reg); //Adresse übergeben
    

    weil in diesem Fall eine Referenz nicht ausreicht.



  • //entweder
    CRgn* Proc(/*...*/) { return &CRgn(); }
    //oder
    HRGN Proc(/*...*/);
    

    edit:
    ein Objekt auf dem Heap anzulegen braucht man nicht (unbedingt), ein lokales Objekt kann man als static deklarieren.



  • Das beste ist, als HRGN zurückzugeben. Man erspart sich 'ne menge Ärger.

    HRGN GetRgn()
    {
      CRgn rgn;
      ...
      return (HRGN) rgn.Detach(); 
    }
    
    CRgn rgn = GetRgn();
    

    @Shlo:
    return &CRgn(...) ist aus zwei Gründen schlecht:

    a) Du gibst die Adresse eines temporären Objekts zurück. Die kann zwar (mit COPY-Semanti) zugewiesen werden, aber da brauch man ja wieder einen Copy-CTor, und ist generell schlechtes Design für eine Funktionssignatur.
    b) Der Destructor von CGdiObject (von dem CRgn abgeleitet ist) ruft DeleteObject() auf - deine gekapselte HRGN ist also schon lange über den Jordan.

    Und noch ein Dritter - die Adresse eines static-Members zurückzugeben geht nur solange gut, wie GetRgn auch nur mit einer Region arbeitet.

    m.e. sind MFC's GDI-Objekt - Wrapperklassen eh' total verhunztund bereiten mehr Kopfschmerzen als vergnügen.



  • Danke für Eure Hilfe!

    Meine Funktion sieht jetzt so aus..

    HRGN BorderRgn(CRgn *SourceRgn)
    {
       CRgn DestRgn;
    
       // ...
    
       return (HRGN) DestRgn.Destach();
    }
    

    soweit so gut.

    nun möchte ich diese Region mit einer schon vorhandenen Region kombinieren...

    CRgn MeineRegion, ZielRegion;
    MeineRegion.CreateRectRgn(50, 50, 100, 100);
    
    ZielRegion.CombineRgn(&MeineRegion, BorderRgn(&MeineRegion), RGN_OR);
    

    Aber der Compiler streigt und sagt ...

    error C2664: 'CombineRgn' : Konvertierung des Parameters 2 von 'struct HRGN__ *' in 'class CRgn *' nicht moeglich

    Kann mir jemmand weiterhelfen 😕

    Danke 🙂



  • ZielRegion.CombineRgn(&MeineRegion, &CRgn(BorderRgn(&MeineRegion)), RGN_OR);
    

    Genau wegen diesem gefummel bevorzuge ich gleich mit HRGN's zu arbeiten..



  • CRgn *CBorder::BorderRgn(CRgn *rgn)
    {
    	CRgn *DestRgn = new CRgn(), SourceRgn; 
    
    	long	i, n, x,  y, size;
    	bool	foundTop, foundBottom, foundLeft, foundRight;
    	RECT	rect, checkrect;
    
    	RGNDATA *RegionData;
    	RECT    *pArray;
    
    	size = GetRegionData(*rgn, sizeof(RGNDATA), NULL);				// Regiongröße ermitteln
    	RegionData = (RGNDATA*) malloc(size);							// Speicher reservieren
    	GetRegionData(*rgn, size, RegionData);							// Daten über Region ermitteln
    
    	pArray = new RECT[(long)RegionData->rdh.nCount];
    
    	for(i = 0; i < (long)RegionData->rdh.nCount; i++)
    	{
    		memcpy(														// RECT in Array speichern
    				&pArray[i], 
    				&RegionData->Buffer[i * sizeof(RECT)],		
    				sizeof(RECT)
    				);
    	}
    
    	DestRgn->CreateRectRgn(0,0,0,0);								// leere Region erzeugen
    
    	// Alle Rechtecke prüfen
    	for(i = 0; i < (long)RegionData->rdh.nCount; i++)
    	{	
    		checkrect = pArray[i];
    
    		// X-Achse
    		for(x = checkrect.left; x < checkrect.right; x++)
    		{
    			foundTop = false;
    			foundBottom = false;
    
    			for(n = 0; n < (long)RegionData->rdh.nCount; n++)
    			{
    				rect = pArray[n];
    
    				// Prüfen ob rect auf x liegt
    				if(rect.left + 1 <= x && rect.right - 2 >= x)
    				{
    					// Prüfen ob rect auf MyRect.top - 1 liegt
    					if(rect.top <= checkrect.top - 1 && rect.bottom - 1 >= checkrect.top - 1)
    					{
    						foundTop = true;
    					}
    
    					// Prüfen ob rect auf MyRect.bottom + 1 liegt
    					if(rect.top <= checkrect.bottom + 1 && rect.bottom >= checkrect.bottom + 1)
    					{
    						foundBottom = true;
    					}
    				}
    			}
    
    			if(!foundTop)
    			{
    				SourceRgn.CreateRectRgn(x, checkrect.top, x + 1, checkrect.top + 1);
    				DestRgn->CombineRgn(DestRgn, &SourceRgn, RGN_OR);
    			}
    
    			if(!foundBottom)
    			{
    //				SourceRgn.CreateRectRgn(x, checkrect.bottom, x + 1, checkrect.bottom - 1);
    //				DestRgn->CombineRgn(DestRgn, &SourceRgn, RGN_OR);
    			}
    		}
    
    		// Y-Achse
    		for(y = checkrect.top; y < checkrect.bottom; y++)
    		{
    			foundLeft = false;
    			foundRight = false;
    
    			for(n = 0; n < (long)RegionData->rdh.nCount; n++)
    			{
    				rect = pArray[n];
    
    				// Prüfen ob rect auf y liegt
    				if(rect.top <= y && rect.bottom - 1 >= y)
    				{
    					// Prüfen ob rect auf MyRect.left - 1 liegt
    					if(rect.left <= checkrect.left - 1 && rect.right - 1 >= checkrect.left - 1)
    					{
    						foundLeft = true;
    					}
    
    					// Prüfen ob rect auf MyRect.right + 1 liegt
    					if(rect.left <= checkrect.right + 1 && rect.right - 1 >= checkrect.right + 1)
    					{
    						foundRight = true;
    					}
    				}
    			}
    
    			if(!foundLeft)
    			{
    				//SourceRgn.CreateRectRgn(checkrect.left, y, checkrect.left + 1, y + 1);
    				//DestRgn->CombineRgn(DestRgn, &SourceRgn, RGN_OR);
    			}
    
    			if(!foundRight)
    			{
    				//SourceRgn.CreateRectRgn(checkrect.right, y, checkrect.right - 1, y + 1);
    				//DestRgn->CombineRgn(DestRgn, &SourceRgn, RGN_OR);
    			}
    		}
    	}
    
    	// DeleteObject(SourceRgn);
    
    	delete [] pArray;
    
    	return DestRgn;
    }
    

    Warum stürtzt wenn ich diese Funktion aufrufe immer mein Programm ab ?
    Hab schon alles ausprobiert aber es stürtzt immer ab.



  • wo stürzt es ab, wie, und schon mal mit dem Debugger eingekreist???



  • SourceRgn.CreateRectRgn(x, checkrect.top, x + 1, checkrect.top + 1);

    es passiert weil ich die SourceRgn mehrmals verwende!
    Ich habe Sie in einer for-Schleife und setze sie jeweils auf ein neues Rechteck.

    Als ich alles mit HRGN's gemacht hab, hat es funktioniert.
    Nur jetzt mit CRgn funktioniert es nicht mehr.

    Weißt du wie ich diesen Fehler beheben kann ?


Anmelden zum Antworten