// File "BDtest.cc". By KWR. Illustrates pointer semantics, inheritance, // and dynamic dispatch ("virtual functions" in C++ lingo). For CSE250 S'00. // Read together with "BDtest.java" for Java-to-C++ translation examples. #include #include #include #include ///needed for "dynamic_cast" translating Java "instanceof" using namespace std; ///redundant on our system? ///*--------------------------------Add these to your code------------------- #include // for sprintf string ftoa(double x) { //Converts float or double to an ANSI string. char b[100]; sprintf(b, "%f", x); string s = b; return s; } //This code and itoa based on Cay Horstmann, /Computing Concepts with C++/ string itoa(long int x) { //Converts [long, short] int to an ANSI string. char b[100]; sprintf(b, "%d", x); string s = b; return s; } bool isWhitespace(char c){return c==' ' || c=='\n' || c=='\t' || c=='\0';} string trim(string str) { int i = 0; int j = str.length() - 1; ///in C++, length is a method too. while (isWhitespace(str.at(i)) && i < j) i++; if (i==j) return ""; //string is all whitespace else { //in this case str.at(i) != whitespace and acts as a while (isWhitespace(str.at(j))) j--; //sentinel, so need not say j >= i return str.substr(i,j-i+1); //take j-i+1 chars from position i } } bool startsWith(string str, string prefix) { return str.find(prefix) == 0; } bool endsWith(string str, string suffix) { return str.rfind(suffix) == str.length()-1; } //*/--------------------------End of stuff to put in your code-------------- class Base { //int value = 0; ///can do this in Java but NOT in C++... int value; ///must initialize by construction OR "outside the class" public: //Base() {} ///Legal in C++, but would not translate Java Base() : value(0) { } ///since C++ does not default-initialize fields Base(int v) : value(v) { } ///C++ initializer syntax not legal in Java ///destructor ~Base() not needed since class holds no pointers. virtual int getValue() const { return value; } virtual void setValue(int v) { value = v; } ///a "mutator"---not const! virtual string toString() const { return "I'm from Base Class! "; } ///^^^Not an automatic conversion in C++ as in Java. Here's the C++ lingo: virtual operator const char*() const { return "Base Class! "; } ///Alas, they haven't built-in automatic conversion to ANSI "string" type: virtual operator /*const*/ string() const { return "Class Base! "; } static string greeting() { return "Hello from Base"; } }; class Derived : public Base { public: Derived() : Base() { } ///C++ uses baseclass name instead of "super" Derived(int v) : Base(v) { } ///super-call can only come before {...} /// This toString() overrides the one in Base. Note "string" is lOWERCASE ///destructor ~Derived() not needed since class holds no pointers. virtual string toString() const {return "I'm from Derived Class! ";} virtual string derivedOnly() const { return "Method \"derivedOnly\" is not defined in the base class."; } virtual operator const char*() const { return "Derived Class! "; } virtual operator /*const*/ string() const { return "Class Derived! "; } static string greeting() {return "Hello from Derived"; } }; void castCheck(Base* base) { ///must come above main() in C++. Derived* dbase = dynamic_cast(base); ///this and next line if (dbase != NULL) { ///translate Java "instanceof" //cout << dynamic_cast(base)->derivedOnly() << endl; cout << dbase->derivedOnly() << endl; } else { cout << "Duck! A run-time \"bad cast\" error is coming!" << endl << "Is the error message as helpful as the Java one was?" << endl; for (int i = 0; i <= 49994999; i++) {} //just for visual delay cout << dynamic_cast(base)->derivedOnly() << endl; //cout << dbase->derivedOnly() << endl; } cerr << "Call to castCheck has terminated OK." << endl; } void stringTest() { string str1 = "New "; string str2 = string("James "); ///equivalent string str3; str3.assign(" Bond: "); ///another way //cout << str1 + str2 + str3 + 200 + 7 << endl; ///C++ "+" cannot do this. cout << str1 + str2 + str3 + "200" + "7" << endl; ///OK str1.append(str2); ///fine: C++ strings are mutable. cout << "With the ANSI indexing convention you get \"" + str1.substr(4,7) << "\"" << endl; ///substr(i,j) means take j chars starting at pos i, ///OR take as many as you can if i+j > length! if (str1 == "New James ") { cout << str1 + "== \"New James \" as expected of objects" << endl; } else { cout << str1 + "!= \"New James \" because both are pointers!" << endl; } if (str3 < str2) { ///C++ has "operator<" built-in for strings. cout << "Compare " +str3+str2+"= " + itoa(str3.compare(str2)) << endl; } if (str3 < str2) { ///The usual comparison operators ARE available. cout << "Compare " + str3 + str2 + "= " << str3.compare(str2) << endl; } cout << "\"" + str3 + "\" gets a trim: \"" + trim(str3) + "\"" << endl; cout << ( startsWith(str3,"Bond") ? "C++ strings are mutable"//() needed! : "C++ strings are immutable" ) << ", and the length of " + str3 + " is now " << str3.length() << endl; ///Note: "___?___:___" binds less than <<, so the () are needed. } int main(int argc, char** argv) { stringTest(); cout << endl; //Base* base1, base2; ///Error: must be "Base *base1, *base2", or better Base* base1; Base* base2;///Can declare class pointers without initializing base1 = new Base(); ///and initialize them later, or declare & init. Derived* derived = new Derived(); ///...in one statement like this. base2 = derived; cout << "base1 says: " + base1->toString() << endl; cout << "base2 says: " + base2->toString() << endl; //since base2 holds a Derived instance, the Derived version is /run/. cout << "Note-(Derived*)base2 prints: " << ((Derived*)base2)->toString() << endl;; //cout << "but (*derived)+*base2 prints: " << ((*derived)+(*base2)) << endl; ///^^^Operator+ seems not to recognize "string" or "const char*" conversions cout << "but (*derived)+*base2 prints: " << (*derived) << *base2 << endl; cout << "and (derived) +*base1 prints: " << (derived) << *base1 << endl; cout << "Now, \"base2 = derived\" uses pointer semantics:" << endl; cout << "Value of \"derived\" now: " << derived->getValue() << endl; cout << "Executing derived->setValue(1); " << endl; derived->setValue(1); cout << "Now base2->getValue() = " << base2->getValue() << endl; cout << "base2 whispers: "; castCheck(base2); cout << "base1 screams: "; castCheck(base1); cout << "Can we make a derived class object say \"base\"?" << endl; cout << base2->greeting() << endl; } //end of main