Figure 1   Passing Character Strings

 class MyClass {
      CString*      m_str;
public:
      MyClass();
      ~MyClass();

      void          SetLPCSTR( LPCSTR lpInputString );
      LPCSTR        GetLPCSTR( );

      void          SetCString( CString csInputString );
      CString       GetCString( );
};

MyClass::MyClass( )
{
      m_str = NULL;
}

MyClass::~MyClass( )
{
      if( m_str )
            delete m_str;
}

LPCSTR MyClass::GetLPCSTR( )
{
      CString      csReturn;
      
      if ( m_str )
            csReturn = *m_str;
            
      return csReturn;
}

void MyClass::SetLPCSTR( LPCSTR lpInputString )
{
      if ( m_str == NULL )
            m_str = new CString( lpInputString );
      else
            *m_str = lpInputString;
}

CString MyClass::GetCString( )
{
      CString      csReturn;
      
      if ( m_str )
            csReturn = *m_str;
            
      return csReturn;
}

void MyClass::SetCString( CString csInputString )
{
      if ( m_str == NULL )
            m_str = new CString( csInputString );
      else
            *m_str = csInputString;
}

Figure 2   strtest.cpp

 ////////////////////////////////////////////////////////////////
// 1996 Microsoft Systems Journal. 
// Written by Paul DiLascia
//
// STRTEST shows what function calls the compiler generates
// for various kinds of CString conversions and assignments.
//
// To see the code the compiler generates, type
//
// cl /c /Fa strtest.cpp
//
// and look at strtest.asm
//

#include <stdio.h>

typedef const char* LPCSTR;

//////////////////
// Stripped-down CString with outline functions instead of 
// inline, to show what happens in the compiled code
//
class CString {
protected:
      LPCSTR m_pchData;   // pointer to string data
public:
      CString();
      CString(const CString& stringSrc);
      CString(LPCSTR lpsz);
      ~CString();
      operator LPCSTR() const;
      const CString& operator= (const CString& cs);
      const CString& operator= (LPCSTR lp);
};

//////////////////
// Some class with get/set methods to access a CString.
//
class MyClass {
      CString m_str;
public:
      void   SetLPCSTR(LPCSTR lp);
      LPCSTR GetLPCSTR();
      void   SetCString(const CString& cs);
      const  CString& GetCString();
};

//////////////// 
// In a real program, these functions would be inline.
// I left them "outline" so you can see where the 
// compiler invokes them.
//
//
LPCSTR MyClass::GetLPCSTR()
{ 
      return m_str;      // invokes CString::operator LPCSTR();
}

const CString& MyClass::GetCString()
{ 
      return m_str;      // just return pointer to m_str;
}

void MyClass::SetLPCSTR(LPCSTR lp)
{ 
      m_str = lp;        // invokes CString::operator=(LPCSTR);
}

void MyClass::SetCString(const CString& cs)
{ 
      m_str = cs;        // invokes CString::operator= (const CString&)
}

void main()
{
      MyClass foo;
      CString cs = "this is a CString";
      LPCSTR  lp = "this is an LPCSTR";
      
      // Four cases for set operation
      foo.SetCString(cs);        // case #1
      foo.SetLPCSTR(cs);         // case #2
      foo.SetCString(lp);        // case #3
      foo.SetLPCSTR(lp);         // case #4
      
      // Four cases for get operation
      cs = foo.GetCString();     // case #5
      cs = foo.GetLPCSTR();      // case #6
      lp = foo.GetCString();     // case #7
      lp = foo.GetLPCSTR();      // case #8
}

Figure 3   strtest.asm

 _main    PROC NEAR
   
      .
      .   prolog, initialization 
      .

;;================ Set functions ================

;; Case #1: foo.SetCString(cs);
;;       -call SetCString (no conversion)
;;
      lea      eax, DWORD PTR _cs$[ebp]
      push     eax
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?SetCString@MyClass@@QAEXABVCString@@@Z ; MyClass::SetCString


;; Case #2: foo.SetLPCSTR(cs);
;;       -first call operator LPCSTR to convert CString->LPCSTR
;;       -call SetLPCSTR
;;
      lea      ecx, DWORD PTR _cs$[ebp]
      call     ??BCString@@QBEPBDXZ                   ; CString::operator LPCSTR
      push     eax
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?SetLPCSTR@MyClass@@QAEXPBD@Z           ; MyClass::SetLPCSTR


;;      Case #3: foo.SetCString(lp);
;;       -first create temp CString T520 
;;       -intialize with constructor CString::CString(LPCSTR)
;;       -call SetCString
;;       -destruct the temp variable.
;;
      mov      eax, DWORD PTR _lp$[ebp]
      push     eax
      lea      ecx, DWORD PTR $T520[ebp]               ; T520 is temp variable
      call     ??0CString@@QAE@PBD@Z                   ; CString::CString
      push     eax
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?SetCString@MyClass@@QAEXABVCString@@@Z ; MyClass::SetCString
      lea      ecx, DWORD PTR $T520[ebp]
      call     ??1CString@@QAE@XZ                      ; CString::~CString


;; Case #4: foo.SetLPCSTR(lp)
;;       -call SetLPCSTR (no conversion)
;;
      mov      eax, DWORD PTR _lp$[ebp]
      push     eax
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?SetLPCSTR@MyClass@@QAEXPBD@Z           ; MyClass::SetLPCSTR
 ;;================ Get functions ================

;; Case #5: cs = foo.GetCString();
;;       -call GetCString
;;       -invoke assignment operator top copy CString
;;
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?GetCString@MyClass@@QAEABVCString@@XZ  ; MyClass::GetCString
      push     eax
      lea      ecx, DWORD PTR _cs$[ebp]
      call     ??4CString@@QAEHABV0@@Z                 ; CString::operator=

;; Case #6: cs = foo.GetLPCSTR();
;;       -call GetCString
;;       -call CString::operator==(LPCSTR)
;;
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?GetLPCSTR@MyClass@@QAEPBDXZ            ; MyClass::GetLPCSTR
      push     eax
      lea      ecx, DWORD PTR _cs$[ebp]
      call     ??4CString@@QAEABV0@PBD@Z               ; CString::operator=


;; Case #7: lp = foo.GetCString();
;;       -call GetCString
;;       -convert result to LPCSTR with CString::operator LPCSTR
;;
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?GetCString@MyClass@@QAEABVCString@@XZ  ; MyClass::GetCString
      mov      ecx, eax
      call     ??BCString@@QBEPBDXZ             ; CString::operator char const *
      mov      DWORD PTR _lp$[ebp], eax


;;      Case #8: lp = foo.GetLPCSTR();
;;       -call GetLPCSTR (no conversion afterwards)
;;
      lea      ecx, DWORD PTR _foo$[ebp]
      call     ?GetLPCSTR@MyClass@@QAEPBDXZ            ; MyClass::GetLPCSTR
      mov      DWORD PTR _lp$[ebp], eax
    


      .
      .   cleanup, return 
      .

_main      ENDP

Figure 7   Conversion Possibilities for Set Functions

Case

Argument Conversion

MFC Conversion

Inside Set Function

1 SetCString(cs)

cs ® const CString&

No conversion, just passes a

The code

pointer to cs.

m_str = cs;

calls

CString::operator=(const

CString&)

which does a quick copy.

Equivalent to

m_str.operator=(cs);

which does

m_str.m_pchData =

cs.m_pchData;

// plus increment ref count

2 SetLPCSTR(cs)

cs ® LPCSTR

Calls inline

The code

CString::operator LPCSTR

m_str = cs;

to convert cs to LPCSTR. This

calls

just gets cs.m_pchData.

CString::operator=(LPCSTR)

Equivalent to:

to allocate and copy bytes.

SetLPCSTR(cs.m_pchData);

Equivalent to:

m_str.operator(lp);

// allocate, copy

3 SetCString(lp)

lp ® const CString&

Creates a temp variable

The code

initialized from

m_str = cs;

CString::CString(LPCSTR)

calls

which allocates and copies

CString::operator=(const

bytes. Equivalent to:

CString&)

CString temp(lp);

which does a quick copy.

// allocate, copy

Equivalent to:

SetCString(temp);

m_str.operator=(cs);

temp.CString::~CString();

which does

This requires calling

m_str.m_pchData =

CString::~CString

cs.m_pchData;

when temp goes out of scope.

// plus increment ref count

The destructor will deallocate

m_pchData if no other CString

is using it.

4 SetLPCSTR(lp)

lp ® LPCSTR

No conversion, just passes

The code

pointer lp.

m_str = lp;

calls

CString::operator=(LPCSTR)

to allocate and copy bytes.

Equivalent to:

m_str.operator=(lp);

// allocate, copy

cs = Cstring

lp = LPCSTR

red = performance hit

Figure 8   Conversion Possibilities for Get Functions

Case

Assignment Conversion

MFC Conversion

Inside Get Function

5 cs=GetCString()

cs ¬ const CString&

Calls

return m_str;

CString::operator=(const

// as const CString&

CString&)

No conversion, just returns

which does a quick copy.

const pointer to m_str.

Equivalent to:

cs.operator=(GetCString());

which does

cs.m_pchData =

GetCString().m_pchData;

// and increment ref count

6 cs=GetLPCSTR()

cs ¬ LPCSTR

Calls

return m_str; // as LPCSTR

CString::operator=(LPCSTR);

Calls

to allocate and copy bytes.

CString::operator LPCSTR

Equivalent to:

(inline)

cs.operator=(GetLPCSTR());

to convert m_str to LPCSTR.

This just gets cs.m_pchData.

Equivalent to:

return m_str.m_pchData

7 lp=GetCString()

lp ¬ const CString&

Calls inline

return m_str;

CString::operator LPCSTR

// as const CString&

to get m_pchData. Equivalent to:

No conversion, just returns

lp = GetCString().m_pchData;

const pointer to m_str.

8 lp=GetLPCSTR()

lp ¬ LPCSTR

No conversion. Simple assignment

return m_str; // as LPCSTR

lp=pointer

Calls

returned.

CSTring::operator LPCSTR

(inline)

to convert m_str to LPCSTR.

This just gets cs.m_pchData.

Equivalent to:

return m_str.m_pchData

cs = Cstring

lp = LPCSTR

red = performance hit