2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

VC++ で マルチバイト文字列とワイド文字列を簡単に変換するライブラリを作ってみた

Posted at

1. はじめに

Visual C++ 環境でプログラムしていると std::string, std::wstring, CStringA, CStringW を使う場面が出てくる。 これらを変換させる個別の関数を作って呼び出していたが 場合分けが 煩わしいので、単純に代入できるクラスを作ってみた。
以下の様な感じで kstring() を介せば型を気にせず代入可能。

main()
{
    string    a ;
    wstring   b ;
    CStringA  c ;
    CStringW  d ;
    
    a = kstring(b) ; a = kstring(c) ; a = kstring(d) ;
    b = kstring(a) ; b = kstring(c) ; b = kstring(d) ;
    c = kstring(a) ; c = kstring(b) ; c = kstring(d) ;
    d = kstring(a) ; d = kstring(b) ; d = kstring(c) ;

2. 概要

std::string を継承する kstringクラス と std::wstring を継承する kwstringクラスを作って、各型からのコンストラクタと 各型へのキャストを定義する。

3. ベースとなる単方向の変換関数

(1) stringwstring

inline std::wstring str_to_wstr(std::string const& src)
{
    vector<wchar_t> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::mbstowcs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::wstring( dest.data() ) ;
}

(2) wstringstring

inline std::string wstr_to_str(std::wstring const& src)
{
    vector<char> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::wcstombs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::string( dest.data() ) ;
}

4. 変換用のクラス

煩雑になるので CStringACStringW は後ほど追加。まずは stringwstring

(1) string の継承クラス kstring を定義

kstring に対し、string, wstring, kwstring とのコンストラクタと キャストを定義。

class kwstring ;	// wstring の継承クラス

class kstring : public std::string
{
public:
    kstring() = default ;

    kstring(const string &str) : string(str) { }

    kstring(const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
    }

    // kwstring 定義後に記述
    inline kstring(const kwstring &kwstr) ;

public:
    operator string()
    {
        return *(string*)this ;
    }

    operator wstring()
    {
        return str_to_wstr( *this ) ;
    }

    // kwstring 定義後に記述
    inline operator kwstring() ;
} ;

kstring の kwstring参照部分の定義で、kwstring の後に記述する

inline kstring::kstring(const kwstring &kwstr)
{
    *(string*)this = wstr_to_str( kwstr ) ;
}

inline kstring::operator kwstring()
{
    return str_to_wstr(*this) ;
}

(2) wstring の継承クラス

kwstring に対し、string, wstring, kstring とのコンストラクタと キャストを定義。

class kwstring : public std::wstring
{
public:
    kwstring() = default ;

    kwstring(const wstring &wstr) : wstring(wstr) { }

    kwstring(const string &str)
    {
        *(wstring*)this = str_to_wstr( str ) ;
    }

    kwstring(const kstring &kstr)
    {
        *(wstring*)this = str_to_wstr( kstr ) ;
    }

public:
    operator wstring()
    {
        return *(wstring*)this ;
    }

    operator string()
    {
        return wstr_to_str( *(wstring*)this ) ;
    }

    operator kstring()
    {
        return wstr_to_str(*this) ;
    }
} ;

5. CStringA と CStringW に対応

CStringACStringW は相互代入が可能なのでこれを利用

(1) kstringを拡張する

kstring に対し、CStringA, CStringW とのコンストラクタと キャストを定義。

    kstring(const CStringA &str)
    {
        *(string*)this = (char*)(LPCSTR)str ;
    }

    kstring(const CStringW &strw)
    {
        *(string*)this = (char*)(LPCSTR)CStringA(strw) ;
    }

    operator CStringW()
    {
        return CStringW( CStringA(this->c_str()) );
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }

(2) kwstringを拡張する

kwstring に対し、CStringA, CStringW とのコンストラクタと キャストを定義。

    kwstring(const CStringW &strw)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)strw ;
    }

    kwstring(const CStringA &str)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)CStringW(str) ;
    }

    operator CStringW()
    {
        return CStringW( this->c_str() ) ;
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }

6. おまけ

(1) kstring, kwstring の出力定義

inline std::ostream & operator << (std::ostream& os, const kstring &str )
{
    os << string(str) ;
    return os ;
}

inline std::wostream & operator << (std::wostream& os, const kwstring &wstr )
{
    os << wstring(wstr) ;
    return os ;
}

(2) operator = を定義すれば 汎用性が増すかな

    kstring & operator = (const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
        return *this ;
    }

(3) Windows APIを使った変換

ベースとなる単方向の変換関数を Windows API を使って作った場合

inline std::wstring StringToWString( const std::string &src )
{
    vector<wchar_t> dest( src.length()+16 ) ;
    ::MultiByteToWideChar( CP_ACP, 0, src.c_str(), -1, dest.data() ,dest.size() );
    return std::wstring( dest.data() ) ;
}

inline std::string WStringToString( const std::wstring &src )
{
    vector<char> dest( src.length()+16 ) ;
    ::WideCharToMultiByte( CP_OEMCP, 0, src.c_str(), -1, dest.data() ,dest.size(), NULL, NULL );
    return std::string( dest.data() ) ;
}

7. ソース一括

#include <vector>
#include <iostream>
#include <cstring>
#include <atlstr.h>

using std::string ;
using std::wstring ;
using std::vector ;
using std::cout ;
using std::wcout ;
using std::endl ;

//-------------------------------------
inline std::wstring str_to_wstr(std::string const& src)
{
    vector<wchar_t> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::mbstowcs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::wstring( dest.data() ) ;
}

inline std::string wstr_to_str(std::wstring const& src)
{
    vector<char> dest( src.length()+16 ) ;
    std::size_t converted ;
    ::wcstombs_s( &converted, dest.data(), dest.size(), src.c_str(), _TRUNCATE ) ;
    return std::string( dest.data() ) ;
}

//-------------------------------------
class kwstring ;	// wstring の継承クラス

class kstring : public std::string
{
public:
    kstring() = default ;

    kstring(const string &str) : string(str) { }

    kstring(const wstring &wstr)
    {
        *(string*)this = wstr_to_str( wstr ) ;
    }

    inline kstring(const kwstring &kwstr) ;

public:
    operator string()
    {
        return *(string*)this ;
    }

    operator wstring()
    {
        return str_to_wstr( *this ) ;
    }

    inline operator kwstring() ;

public:
    kstring(const CStringA &str)
    {
        *(string*)this = (char*)(LPCSTR)str ;
    }

    kstring(const CStringW &strw)
    {
        *(string*)this = (char*)(LPCSTR)CStringA(strw) ;
    }

    operator CStringW()
    {
        return CStringW( CStringA(this->c_str()) );
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
} ;

//-------------------------------------
class kwstring : public std::wstring
{
public:
    kwstring() = default ;

    kwstring(const wstring &wstr) : wstring(wstr) { }

    kwstring(const string &str)
    {
        *(wstring*)this = str_to_wstr( str ) ;
    }

    kwstring(const kstring &kstr)
    {
        *(wstring*)this = str_to_wstr( kstr ) ;
    }

public:
    operator wstring()
    {
        return *(wstring*)this ;
    }

    operator string()
    {
        return wstr_to_str( *(wstring*)this ) ;
    }

    operator kstring()
    {
        return wstr_to_str(*this) ;
    }

public:
    kwstring(const CStringW &strw)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)strw ;
    }

    kwstring(const CStringA &str)
    {
        *(wstring*)this = (wchar_t*)(LPCWSTR)CStringW(str) ;
    }

    operator CStringW()
    {
        return CStringW( this->c_str() ) ;
    }

    operator CStringA()
    {
        return CStringA( this->c_str() ) ;
    }
} ;

//-------------------------------------
inline kstring::kstring(const kwstring &kwstr)
{
    *(string*)this = wstr_to_str( kwstr ) ;
}

inline kstring::operator kwstring()
{
    return str_to_wstr(*this) ;
}

//-------------------------------------
inline std::ostream & operator << (std::ostream& os, const kstring &str )
{
    os << string(str) ;
    return os ;
}

inline std::wostream & operator << (std::wostream& os, const kwstring &wstr )
{
    os << wstring(wstr) ;
    return os ;
}

//-------------------------------------
int main()
{
    string    a =  "abc" ;
    wstring   b = L"ABC" ;
    CStringA  c =  "xyz" ;
    CStringW  d = L"XYZ" ;
    
    a = kstring(b) ; a = kstring(c) ; a = kstring(d) ;
    b = kstring(a) ; b = kstring(c) ; b = kstring(d) ;
    c = kstring(a) ; c = kstring(b) ; c = kstring(d) ;
    d = kstring(a) ; d = kstring(b) ; d = kstring(c) ;

    cout << kstring(b) << endl ;
    wcout << kstring(a) << endl ;

    return 0 ;
}
2
1
5

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?