feil argument konvertering foretrukket når du ringer funksjon

stemmer
3

Jeg skriver et program under MS Visual C ++ 6.0 (ja, jeg vet det er gammelt, nei det er ingenting jeg kan gjøre for å oppgradere). Jeg ser noen oppførsel som jeg tror er veldig rart. Jeg har en klasse med to konstruktører definert slik:

class MyClass
{
public:
    explicit MyClass(bool bAbsolute = true, bool bLocation = false) : m_bAbsolute(bAbsolute), m_bLocation(bLocation) { ; }
    MyClass(const RWCString& strPath, bool bLocation = false);

private:
    bool m_bAbsolute;
    bool m_bLocation;
};

Når jeg instantiate en forekomst av denne klassen med denne syntaksen: MyClass(blah), kaller det første konstruktøren. Som du kan se, la jeg explicitordet til det i håp om at det ikke ville gjøre det ... ingen terninger. Det ser ut til å foretrekke konvertering fra const char *til boolover konvertering til RWCString, som har en kopi konstruktør som tar en const char *. Hvorfor gjør den dette? Jeg vil anta at gitt to mulige valg som dette, ville det si at det er tvetydig. Hva kan jeg gjøre for å hindre den fra å gjøre dette? Hvis det overhodet er mulig, vil jeg gjerne unngå å måtte eksplisitt kaste strPathargument til en RWCString, så det kommer til å bli brukt med liter mye, og det er mye ekstra å skrive (pluss en veldig enkel feil å gjøre).

Publisert på 19/03/2009 klokken 19:39
kilden bruker
På andre språk...                            


7 svar

stemmer
0

Ikke sikker på hvorfor det skal forvirre en referanse til en streng og en bool? Jeg har sett problemer med en bool og en int.
Kan du miste standardverdien for den første konstruktør - det kan være at siden dette er å gjøre den til standard konstruktør for MyClass () så er det også standard hvis den ikke kan matche args

Svarte 19/03/2009 kl. 19:43
kilden bruker

stemmer
-1

Er du sikker på at det virkelig er å kalle den første konstruktør? Kaller du det med strengen hardkodet, eller er det skjult bak en #define? Er du sikker på at #define er hva du tror det er? (Prøv å kompilere med mulighet / Ef å få utvidet preprosessor utgang, og se om samtalen ser ut som du forventer det skal se ut.)

EDIT: Basert på denne og andre kommentarer, er mitt forslag å legge til en annen konstruktør for const char*. Er det mulig?

Svarte 19/03/2009 kl. 19:46
kilden bruker

stemmer
9

Eksplisitt vil ikke hjelpe her som konstruktøren er ikke en del av den implisitte konvertering, bare mottakeren.

Det er ingen måte å kontrollere den foretrukne rekkefølgen av konverteringer, men du kan legge til en andre konstruktør som tok en const char *. Eg:

class MyClass
{
public:
    MyClass(bool bAbsolute = true, bool bLocation = false);
    MyClass(const RWCString& strPath, bool bLocation = false);
    MyClass(const char* strPath, bool bLocation = false);

private:
    bool m_bAbsolute;
    bool m_bLocation;
};
Svarte 19/03/2009 kl. 19:50
kilden bruker

stemmer
1

Hvis du skjønner; t vil beholde avstøpning det, så det virker for meg at du kanskje må foreta en ny ctor som tar en const char *.

Det er hva jeg ville sannsynligvis gjøre i denne situasjonen.

(Ikke sikker på hvorfor du gjør en ctor med en type som du ikke er bestått for det meste av bruken.)

redigere:

Jeg ser noen andre allerede postet dette mens jeg skriver min

Svarte 19/03/2009 kl. 19:54
kilden bruker

stemmer
0

Dine valg er å legge til en konstruktør som eksplisitt tar en const char *

MyClass(const char* strPath, bool bLocation = false); // Thanks Andrew Grant!

eller gjøre

MyClass( string("blah") );

Kompilatoren egentlig vet hvordan å gjøre en const char * til en bool. Det måtte gå på jakt for å se om, for noen av de første argument typer MyClass konstruktører, det er en konstruktør som vil ta kildetype du har gitt det, eller om det kan kaste det for en type som er akseptert av noen av konstruktører av noen av de første argument typer dine MyClass konstruktører, eller ... vel, du ser hvor dette går, og det er bare for det første argumentet. På den måten ligger galskap.

Svarte 19/03/2009 kl. 20:08
kilden bruker

stemmer
0

Den explicitordet forteller kompilatoren kan ikke konvertere en verdi av argumentet type til et objekt av klassen implisitt, som i

struct C { explicit C( int i ): m_i(i) {}; int m_i; };
C c = 10;//disallowed
C c( 2.5 ); // allowed

C ++ har et sett med regler for å avgjøre hva konstruktøren er å bli kalt i ditt tilfelle - Jeg vet ikke fra baksiden av hodet mitt, men du kan intuitivt se at standard argumentene lede mot tvetydighet.

Du må tenke disse mislighold gjennom.

Du kan fallback på noen statisk, oppkalt, byggemetoder. Eller du kan bruke en annen klasse (som ikke er et dårlig valg fra et design synspunkt). I uansett, la deg klientkoden bestemme hvilken konstruktøren å bruke.

struct C {
  static C fromString( const char* s, const bool b = true );
  static C fromBools( const bool abs = true, const bool b = true );
};

eller

struct CBase {
    bool absolute; 
    bool location;
    CBase( bool abs=true, bool loc=true );
};

struct CBaseFromPath {
    // makes 'absolute' true if path is absolute
    CBaseFromPath( const char* s, const bool loc );
};
Svarte 19/03/2009 kl. 20:14
kilden bruker

stemmer
6

Andrew Grant gitt løsningen. Jeg ønsker å fortelle deg hvorfor det ikke fungerer slik du prøvde. Hvis du har to levedyktige funksjoner for et argument, da den som passer argumentet beste kalles. Den andre krever en brukerdefinert omdanning, mens den første trenger bare en standard konvertering. Det er derfor kompilatoren foretrekker den første over den andre.

Svarte 19/03/2009 kl. 20:16
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more