Check alle échte Black Friday-deals Ook zo moe van nepaanbiedingen? Wij laten alleen échte deals zien

[C++]list.sort op lijst met pointers

Pagina: 1
Acties:
  • 317 views sinds 30-01-2008
  • Reageer

  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
Hallo, ik heb het volgende probleempje.

Ik heb een klasse product. En voor product heb ik de operators < geoverload.

Dus als ik nu een list van producten zou maken, dan kan eenvoudig via de ingebouwde sort de lijst sorteren. Nu heb ik echter geen list van producten, maar van pointers naar producten.

En op pointers naar producten kan je de < operator niet overloaden, want die bestaat al (vergelijkt geheugenadressen). Is er een manier om dit toch te doen?

Stukje code:
C++:
1
2
3
4
5
6
7
8
9
Product::operator<(const Product prod){return naam < prod.naam;} // naam is private member van Product

list<Product> lijst;
// voeg wat elementen toe;
lijst.sort(); // => werkt.

list<Product*> lijst2;
//voeg wat elementen toe
lijst.sort(); // geeft uiteraard niet de gewenste ressultaten terug;


Iemand enig idee hoe ik dit toh kan laten werken?

bool operator<(Product*, Product*); mag immers niet.

Sorry, maar ben nieuw met c++.

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
C++:
1
2
3
4
5
6
7
8
9
10
class Product{
public:
    // de rest

    bool operator()(Product *a_Left, Product *a_Right){
        return a_Left->naam < a_Right->naam;
    }
};

lijst.sort(Product());

  • ATS
  • Registratie: September 2001
  • Laatst online: 28-11 20:56

ATS

Beetje afhankelijk van je sort functie. Vaak kan je aan sort functies een pointer naar een vergelijkingsfunctie mee geven. Het schrijven van zo'n vergelijkingfunctie is natuurlijk triviaal.
Maareh, waarom mag volgens jou een herimplementatie van < op pointers naar een bepaalde klasse niet? Ik weet niet zo zeker dat dat niet kan eigenlijk.

My opinions may have changed, but not the fact that I am right. -- Ashleigh Brilliant


  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
Ik heb het geprobeerd, maar de compiler (g++ op cygwin) komt dan reclameren dat dat niet mag. Ik kan hier niet meteen de exate foutmelding neerschirjven. Ik zal dat wevens wel doen.

at Prisoner Of Pain. Mercie, ik zal je oplossing eens bekijken.

De sortfunctie gebruik ik van die van list uit de stl. Die werkt via <. Als je een lijst wil sorteren dan moet je zien dat de < operator gedefinieerd is voor de objecten in de lijst.

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

PrisonerOfPain schreef op vrijdag 30 november 2007 @ 15:22:
C++:
1
2
3
4
5
6
7
8
9
10
class Product{
public:
    // de rest

    bool operator()(Product *a_Left, Product *a_Right){
        return a_Left->naam < a_Right->naam;
    }
};

lijst.sort(Product());
Waarom zou je de predicate in hemelsnaam in Product definieren? Nou ben je verplicht een Product aan te maken om mee te geven aan sort(), en bovendien krijgt Product daardoor een verder zinloze operator(). Stop die dan gewoon in een andere class.

En dan natuurlijk generiek, zodat je iedere container bestaande uit pointers ermee kunt sorten ;)
C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class T, class P = std::less<T> >
struct ptr_less : public std::binary_function<const T*, const T*, bool>
{
    ptr_less() : pred() { }
    ptr_less(P p) : pred(p) { }

    bool operator()(const T * pLeft, const T * pRight) { return pred(*pLeft, *pRight); }

private:
    P pred;
};

// ...
lijst.sort(ptr_less<Product>());

[ Voor 5% gewijzigd door .oisyn op 30-11-2007 17:20 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

ATS schreef op vrijdag 30 november 2007 @ 15:49:
Beetje afhankelijk van je sort functie. Vaak kan je aan sort functies een pointer naar een vergelijkingsfunctie mee geven. Het schrijven van zo'n vergelijkingfunctie is natuurlijk triviaal.
Maareh, waarom mag volgens jou een herimplementatie van < op pointers naar een bepaalde klasse niet? Ik weet niet zo zeker dat dat niet kan eigenlijk.
pointers zijn built-in types, en ten minste 1 parameter van een overloaded operator moet een UDT zijn.
Zoutvat schreef op vrijdag 30 november 2007 @ 16:56:
De sortfunctie gebruik ik van die van list uit de stl. Die werkt via <. Als je een lijst wil sorteren dan moet je zien dat de < operator gedefinieerd is voor de objecten in de lijst.
De sortfunctie zonder parameters gebruikt std::less<T>, die idd standaard < gebruikt. Je zou std::less kunnen specializen voor Product*, maar dan geldt dat voor alle containers die pointers naar Products willen vergelijken (omdat de hele STL standaard std::less gebruikt). Imho kun je het beste de sort() functie mét parameter gebruiken, zoals PrisonerOfPain al liet zien.

[ Voor 38% gewijzigd door .oisyn op 30-11-2007 17:19 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
Heb zonet de oplossing pop geprobeerd, maar kijg het volgende:
code:
1
2
3
4
5
C:\blabla>g++ -c product.cpp productenlijst.cpp test.cpp
productenlijst.cpp: In member function `void Kookboek::Productenlijst::SorteerAlfabetisch()':
productenlijst.cpp:64: error: no matching function for call to `Kookboek::Product::Product()'
product.h:18: note: candidates are: Kookboek::Product::Product(const Kookboek::Product&)
product.h:20: note:  Kookboek::Product::Product(std::string)


Ik heb een constructor gedefinieerd die een string als parameter gebruikt.
Sorry als ik een beetje Noob ben, maar ben nog helemaal niet bekend met C++. Dit is het eerste programma dat meer dan 2 files bevat.

op regel 64 staat "pLijst.sort(Product());"
op regel 20 "Product(string);" (als constructor)
op regel 18 enkel het {teken net na class Product (?)

;( programmeren is niet leuk als het niet wil lukken.

[ Voor 17% gewijzigd door Teun_2 op 30-11-2007 18:04 ]


  • user109731
  • Registratie: Maart 2004
  • Niet online
Zoutvat schreef op vrijdag 30 november 2007 @ 18:01:
Heb zonet de oplossing pop geprobeerd, maar kijg het volgende:
code:
1
productenlijst.cpp:64: error: no matching function for call to `Kookboek::Product::Product()'

op regel 64 staat "pLijst.sort(Product());"
op regel 20 "Product(string);" (als constructor)
De foutmelding is best duidelijk: op regel 64 roep je de constructor van Product aan... Die bestaat echter niet, want je hebt alleen een copy constructor en een constructor die een std::string verwacht gedefinieert.

Het handigste is om wat meer informatie over de sort-functie te zoeken :)

[ Voor 13% gewijzigd door user109731 op 30-11-2007 18:15 ]


  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
Zover was ik al wel :)

Hoe krijg ik nu die sort zover dat hij de "bool operator()(Product *a_Left, Product *a_Right)" gebruikt om te sorteren?

Enorm hard bedankt al voor de hulp! Ik vind het echt geweldig dat er mensen zijn die me hierbij gewoon helpen! Thx

  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
PrisonerOfPain schreef op vrijdag 30 november 2007 @ 15:22:
C++:
1
2
3
4
5
6
7
8
9
10
class Product{
public:
    // de rest

    bool operator()(Product *a_Left, Product *a_Right){
        return a_Left->naam < a_Right->naam;
    }
};

lijst.sort(Product());
Dus dit, dan roep je toch de constructor op van product? :?

  • user109731
  • Registratie: Maart 2004
  • Niet online
Zoiets zou moeten werken:
C++:
1
2
3
4
bool compareProducts(Product *a_Left, Product *a_Right){
  return a_Left->naam < a_Right->naam;
} 
lijst.sort(compareProducts); 

edit: over .oisyn's code heengekeken, maar die is leuker :P

[ Voor 30% gewijzigd door user109731 op 30-11-2007 18:24 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Zoutvat schreef op vrijdag 30 november 2007 @ 18:01:
Heb zonet de oplossing pop geprobeerd
Waarom, heb je mijn reactie niet gelezen? De oplossing van PoP is niet de manier om dit soort dingen aan te pakken. Het feit dat je nu een default ctor aan je class toe moet gaan zitten voegen zegt al genoeg :)
Zoutvat schreef op vrijdag 30 november 2007 @ 18:15:

Dus dit, dan roep je toch de constructor op van product? :?
De sort-functie verwacht een predicate. Dat kan een functie of een functor zijn. Een functor is een object met een overloaded operator(), zodat je het eigenlijk aan kunt roepen als een functie. Met die haakjes roep je idd indirect de constructor aan, maar je moet het vooral zien als dat je gewoon een object aanmaakt die aan de functie mee wordt gegeven. Dat object, een Product, heeft een operator(), en wordt dus in sort() als functor gebruikt. Het is dus niet zo dat de constructor ineens als vergelijkingsfunctie wordt gebruikt oid :). Maar die manier is sowieso onhandig, die compare-functie hoort niet in je Product. Je hebt natuurlijk geen Product nodig om twee ándere Products te kunnen vergelijken. De oplossing van JanDM is het simpelst - definieer gewoon een functie die de compare uitvoert, en geef die functie aan sort() mee.

[ Voor 58% gewijzigd door .oisyn op 30-11-2007 18:50 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
*O* O+ *O* d:)b
Had nog nooit van functor gehoord :P

Maar nu werkt het wel. Bedankt!

[ Voor 67% gewijzigd door Teun_2 op 30-11-2007 19:16 ]


  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
.oisyn schreef op vrijdag 30 november 2007 @ 17:09:
[...]


Waarom zou je de predicate in hemelsnaam in Product definieren? Nou ben je verplicht een Product aan te maken om mee te geven aan sort(), en bovendien krijgt Product daardoor een verder zinloze operator(). Stop die dan gewoon in een andere class.
De enige reden was dat naam private was, volgens de comments. En aangezien ik vind dat friend een overtreding van de encapulatie 'regels' is, besloot ik om 't een member van Product te maken. Normaal had ik er een apart _CmpProduct struct (oid) van gemaakt.

  • Soultaker
  • Registratie: September 2000
  • Laatst online: 05:14
Misschien mosterd na de maaltijd, maar die functor is meestal overbodig en maakt het vaak alleen maar ingewikkelder. (Wel handig als je at runtime wil configureren op welke criteria gesorteerd wordt.) Zo simpel kan het ook:
C++:
1
2
3
4
5
6
7
8
bool cmp(const Product *p, const Product *q)
{
        return *p < *q;
}

..

lijst.sort(cmp);

(Ik heb nooit precies begrepen waarom dit soort functies zowel een functie als een object als argument accepteren, maar in principe is dat ook niet nodig om er gebruik van te maken).

edit:
D'oh, JanDM's reactie over het hoofd gezien. 8)7

[ Voor 5% gewijzigd door Soultaker op 01-12-2007 15:22 ]


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

PrisonerOfPain schreef op zaterdag 01 december 2007 @ 02:02:
En aangezien ik vind dat friend een overtreding van de encapulatie 'regels' is
Sorry maar dat vind ik dus werkelijk nergens op slaan :). Een friend breekt juist niet de encapsulatie-regel, dat zou pas gebeuren als je het atribuut public maakt. De maker van Product levert een compare functie, dus dan kan die best friend zijn. Verder had Product al een publieke operator< geoverload, dus die kan een compare-functie die werkt op pointers gewoon ook gebruiken door de pointers te dereferencen. Daarnaast had je ook nog een normale static functie als member kunnen maken, zodat je nog altijd geen Product hoeft te maken en niet elke Product ineens een functor is.
Klopt, JanDM laat precies dat zien ;)
(Ik heb nooit precies begrepen waarom dit soort functies zowel een functie als een object als argument accepteren, maar in principe is dat ook niet nodig om er gebruik van te maken).
Waarom niet? Het zijn template functies, dus in plaats van dat het template type wordt gededuceerd als ProductCompare (oid) wordt het juist gededuceerd als bool (*)(const Product*, const Product*).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • Soultaker
  • Registratie: September 2000
  • Laatst online: 05:14
Ik heb er geen goede reden voor, maar ik denk er meestal niet aan dat je een template ook met een functietype kunt instantiëren en dat een functie zich op dezelfde manier tot zijn type verhoudt als een object tot zijn klasse.

  • Teun_2
  • Registratie: Oktober 2003
  • Laatst online: 24-11 21:33
PoP, de naam is ook te verkrijgen met een Getfunctie. C++ is best een lekker uitgebreide taal. Maar 't leert best wel vlot. Bedankt voor de hulp

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 03:22

.oisyn

Moderator Devschuur®

Demotivational Speaker

Soultaker schreef op zondag 02 december 2007 @ 16:32:
Ik heb er geen goede reden voor, maar ik denk er meestal niet aan dat je een template ook met een functietype kunt instantiëren en dat een functie zich op dezelfde manier tot zijn type verhoudt als een object tot zijn klasse.
't Is ook geen functie, 't is een functie-pointer, en da's gewoon een object als alle andere. Maar ook functie-types zelf kun je gewoon als template parameter meegeven, heel boost::function is daarop gebaseerd: boost::function<void(int, float)>. Uiteraard kun je geen object van een functie type definieren (wel declareren trouwens - het is dan gewoon een functie-declaratie, maar dan weer niet als het type van een template parameter komt), maar bijv. wel een pointer daarnaar.

[ Voor 8% gewijzigd door .oisyn op 03-12-2007 12:08 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.

Pagina: 1