From oleg Tue May 31 09:30:42 CDT 1994 Newsgroups: comp.sys.mac.programmer Subject: "Magical" conversion from (char *) to Pascal string in C++ Summary: "Transparent" incorporation of Mac OS data structures into C++ classes Followup-To: Distribution: Organization: University of North Texas, Denton Keywords: Pascal strings, Rectangle, C++, class library Cc: Status: RO There has been some discussion recently about conversion of a C string to the Pascal string and correctly casting of the result. I thought I'd throw in my couple of cents: First, let's define the following class class Pstr // Pascal String, this is just a type conversion { Str255 pas_string; public: Pstr(const char * c_str); ~Pstr(void) {} operator unsigned char const * () { return pas_string; } }; // Used to "implicitly" convert from C to Pstr::Pstr(const char * c_str) // Pascal string { strncpy((char *)pas_string,c_str,sizeof(*this)-2); CtoPstr((char *)pas_string); } After that, one can write smth like that char * title = "some title"; this_window = NewWindow(nil,rect += window_offset,(Pstr)title,....etc) It is THAT simple: just putting (Pstr) before a C string magically converts it to a Pascal string and "does" correct casting, while keeping the original C string intact. The way I figure it, (Pstr)title should make an object of type Pstr from 'title' by applying the Pstr::Pstr(const char * c_str) constructor. Since NewWindow() requires a pascal string as its third argument, the operator 'unsigned char const *' would apply, which gives exactly what NewWindow() wants. And here how it actually works (peeked from the object code generated by the Symantec C++ compiler): the compiler allocates 256 bytes on stack, copies the C string in there, calls CtoPstr(), and then pushes the address of that temporary PASCAL string into stack for NewWindow(). After the NewWindow() returns, the temporary space allocated for the Pascal string is disposed of (by simply incrementing A7, mind you). To me, it looks exactly as I wanted: conversion of a C string into the PASCAL one without messing up the C string. Here is more of the same idea: class ScreenRect : public Rect { public: ScreenRect(const Rect& rect) { *this = *(ScreenRect *)▭ } ScreenRect(const rowcol& heightwidth); ~ScreenRect(void) {} ScreenRect& operator += (const int offset); operator Rect * (void) { return this; } void print(const char * title = "") const; }; // Create a rectangle of given height/width // positioned at the origin ScreenRect::ScreenRect(const rowcol& heightwidth) { left = top = 0; bottom = heightwidth.row(); right = heightwidth.col(); } // Shifting a rectangle by the same amount // in X and Y ScreenRect& ScreenRect::operator += (const int offset) { top += offset; bottom += offset; left += offset; right += offset; return *this; } Then I can write ScreenRect sub_horizon(q_bounds()); sub_horizon.print("sub horizon"); EraseRect(sub_horizon); or, even crazier, ScreenWindow::ScreenWindow(ScreenRect rect, const char * title) { const int window_offset = 100; // Cannot be 0 or small! this_window = NewWindow(nil,rect += window_offset,(Pstr)title,... } So, all QuickDraw functions AUTOMATICALLY accept ScreenRect as if it were Rect *. This way, one can build C++ classes around all QuickDraw (and other OS) data types, and one can still use original QuickDraw functions on the new "objects". I've done just that for a few OS data types, I can post it if there is some interest. BTW, this all is perfectly legal C++ and would work everywhere. The code snippets in this post are fragments of an actual working program. It compiles with Symantec C++ versions 6.0, 6.0.1, and 7.0. Oleg P.S. I'm not a frequent reader of this newsgroup, please send any comments to oleg@ponder.csci.unt.edu or oleg@unt.edu