酒鬼随机漫步(一个矢量类)
这是一个定义的一个矢量类, 然后用矢量类模拟一个酒鬼的随机漫步
问题很简单, 实现也不麻烦, 但是这个小程序却可以呈现出许多语法知识。而且代码风格也不错,因此保存在了这篇博客中。
建议:
1. 类的声明以及函数的声明放到一个文件夹内, 并且在一些必要的地方加上注释!
2. 函数的实现放到另一个文件内。
3. 将程序要具体解决的问题放到另外的一个文件里。(详见代码!)
好处: 把类的接口和实现细节分离开, 易于更改某个函数的功能。
把函数的声明和定义分开, 提高代码可读性。
把类的声明和定义 与 要解决的问题分开, 提高,类的重用性!
定义类(声明类内的函数)
// vect.h -- Vector class with <<, mode state #ifndef VECTOR_H_ #define VECTOR_H_ #include <iostream> namespace VECTOR { class Vector { public: enum Mode{RECT, POL}; // RECT for rectangular, POL for Polar modes private: double x; // horizontal value double y; // vertical value double mag; // length of vector in degrees double ang;// direction of vector in degrees Mode mode; // private methods for setting values void set_mag(); void set_ang(); void set_x(); void set_y(); public: Vector(); Vector(double n1, double n2, Mode form = RECT); void reset(double n1, double n2, Mode form = RECT); ~Vector(); double xval() const {return x; } // report x value double yval() const {return y; } // report y value double magval() const {return mag; } // report magnitude double angval() const {return ang; } // report angle void polar_mode(); // set mode to POL void rect_mode(); // set mode to RECT // operator overloading Vector operator+(const Vector & b) const; Vector operator-(const Vector & b) const; Vector operator-()const; Vector operator*(double n) const; // friends friend Vector operator*(double n, const Vector & a); friend std::ostream & operator<<(std::ostream & os, const Vector & v); }; } // end namespace VECTOR #endif
上面代码涵盖了许多关于类的基础知识: 名称空间与作用域 , 实现类内部常量的方法, 构造函数, 析构函数, 运算符重载, 友元函数, 关于多种实现方法等。
PS: 实现类内部常量的方法: (1)枚举类型。 (2) static const int 常量
运算符重载: 注意操作数的顺序。
函数定义
// vect.cpp -- methods for the Vector class #include <cmath> #include "vect.h" // include <iostream> using std::sqrt; using std::sin; using std::cos; using std::atan; using std::atan2; using std::cout; namespace VECTOR { // compute degree in one radian const double Rad_to_deg = 45.0/atan(1.0); // should be about 57.2957795130823 // private methods // calculate magnitude from x and y void Vector::set_mag() { mag = sqrt(x*x + y*y); } void Vector::set_ang() { if(x == 0.0&& y== 0.0) ang = 0.0; else ang = atan2(y, x); } //set x from polar coordinate void Vector::set_x() { x = mag*cos(ang); } //set y from polar coodinate void Vector::set_y() { y = mag * sin(ang); } // public methods Vector::Vector() // default constructor { x = y = mag = ang = 0.0; mode = RECT; } // construct vector from rectangular coordinates if form is r // (the default) or else from polar coordinates if form is p Vector::Vector(double n1, double n2, Mode form) { mode = form; if(form == RECT) { x = n1; y = n2; set_mag(); set_ang(); } else if(form == POL) { mag = n1; ang = n2/Rad_to_deg; set_x(); set_y(); } else { cout << "Incorrect 3rd argument to Vector() --"; cout << "vector set to 0.0"; mode = RECT; } } // reset vector from rectangular coodinates if form is // RECT (the default) or else form polar coordinates if // form is POL void Vector::reset(double n1, double n2, Mode form) { mode = form; if(form == RECT) { x = n1; y = n2; set_mag(); set_ang(); } else if (form == POL) { mag = n1; ang = n2/Rad_to_deg; set_x(); set_y(); } else { cout << "Incorrect 3rd argument to Vector() -- "; cout <<"vector set to 0.0\n"; x = y = mag = ang = 0.0; mode = RECT; } } Vector::~Vector() // destructor { } void Vector::polar_mode() //set to polar mode { mode = POL; } void Vector::rect_mode()// set to rectangular mode { mode = RECT; } // operator overloading // add two Vectors Vector Vector::operator+(const Vector & b) const { return Vector(x + b.x, y + b.y); } //subtract Vector b from a Vector Vector::operator-(const Vector & b) const { return Vector(x-b.x, y-b.y); } // reverse sign of Vector Vector Vector::operator-() const { return Vector(-x, -y); } // multiply vector by n Vector Vector::operator*(double n) const { return Vector(n*x, n*y); } // friend methods // multiply n by Vector a Vector operator*(double n, const Vector & a) { return a * n; } //display rectangular coordinates if mode is RECT // else display polar coordinates if mode is POL std::ostream & operator<<(std::ostream & os, const Vector & v) { if (v.mode == Vector::RECT) os << "(x,y) = (" << v.x << ", " << v.y << ")"; else if (v.mode == Vector::POL) { os << " (m,a) = (" << v.mag << ", " << v.ang*Rad_to_deg << ")"; } else os << "Vector object mode is invalid"; return os; } } // end namespace VECTOR
具体解决的问题
// randwalk.cpp -- using the Vector class // compile with the vect.cpp file #include <iostream> #include <cstdlib> // rand(), srand() pototypes #include <ctime> // time() pototype #include "vect.h" int main() { using namespace std; using VECTOR::Vector; srand(time(0)); // seed random-number generator double direction; Vector step; Vector result(0.0, 0.0); unsigned long steps = 0; double target; double dstep; cout << "Enter target distance (q to quit): "; while(cin >> target) { cout << "Enter step length: "; if(!(cin>>dstep)) break; while(result.magval() < target) { direction = rand()%360; step.reset(dstep, direction, Vector::POL); result = result + step; steps++; } cout << "After " << steps <<" steps, the subject " "has the following location:\n"; cout << result <<endl; result.polar_mode(); cout << "or\n" << result << endl; cout << "Average outward distance per step = " << result.magval()/steps << endl; steps = 0; result.reset(0.0, 0.0); cout << "Enter target distance (q to quit): "; } cout << "Bye!\n"; cin.clear(); while(cin.get() != '\n') continue; return 0; }
二。一个简易的string类。
锻炼内容:
拷贝构造函数(深拷贝与浅拷贝)
重载赋值运算符(深赋值)
许多的细节与技巧!
类的声明
//sting1.h -- fixed and augmented string class definition #ifndef STRING1_H_ #define STRING1_H_ #include <iostream> using std::ostream; using std::istream; class String { private: char * str; // pointer ot string int len; // length of string static int num_strings; // number of objects static const int CINLIM = 80; // cin input limit public: // construction and other methods String(const char * s); // constructor String(); // default constructor String(const String &); // copy constructor ~String(); // destructor int length() const { return len; } // overloaded operator methods String & operator=(const String &); String & operator=(const char *); char & operator[](int i); const char & operator[](int i)const; // overloaded operator friends friend bool operator<(const String &st, const String &st2); friend bool operator>(const String &st1, const String &st2); friend bool operator==(const String &st, const String &st2); friend ostream & operator<<(ostream & os, const String & st); friend istream & operator>>(istream & is, String & st); //static function static int HowMany(); }; #endif
类方法的实现。
// string1.cpp -- String class methods #include <cstring> // string.h for some #include "string1.h" // includes <iostream> using std::cin; using std::cout; // initializing static class member int String::num_strings = 0; // static method int String::HowMany() { return num_strings; } // class methods String::String(const char * s) // construct String from C string { len = std::strlen(s); // set size str = new char[len + 1]; // allot storage std::strcpy(str, s); // initialize pointer num_strings++; // set object count } String::String() // default constructor { len = 4; str = new char[1]; str[0] = '\0'; // default string num_strings++; } String::String(const String & st) { num_strings++; // handle static member update len = st.len; // same length str = new char [len + 1]; // allot space std::strcpy(str, st.str); // copy string to new location } String::~String() // necesserary destructor { --num_strings; // required delete [] str; // required } // overloaded operator methods // assign a String to a String String & String::operator=(const String & st) { if(this == &st) return *this; delete [] str; len = st.len; str = new char[len + 1]; std::strcpy(str, st.str); return *this; } // assign a C string to a String String & String::operator=(const char * s) { delete [] str; len = std::strlen(s); str = new char[len + 1]; std::strcpy(str, s); return *this; } // read-write char access for non-const String char & String::operator[](int i) { return str[i]; } // read-only char access for const string const char & String::operator[](int i) const { return str[i]; } // averloaded operator friends bool operator<(const String &st1, const String &st2) { return (std::strcmp(st1.str, st2.str) < 0); } bool operator>(const String &st1, const String &st2) { return st2 < st1; } bool operator==(const String &st1, const String &st2) { return (std::strcmp(st1.str, st2.str)==0); } // simple String output ostream & operator<<(ostream & os, const String & st) { os << st.str; return os; } // quick and dirty String input istream & operator>>(istream & is, String & st) { char temp[String::CINLIM]; is.get(temp, String::CINLIM); if(is) st = temp; while (is && is.get() != '\n') continue; return is; }
main(), 测试String类。
// saying1.cpp -- using expanded String class // complile with string1.cpp #include <iostream> #include "string1.h" const int MaxLen = 81; int main() { using std::cout; using std::cin; using std::endl; String name; cout << "Hi, what's your name?\n>> "; cin >> name; cout << name << ", please enter up to " << ArSize << " short sayings <empty line to quit>:\n"; String sayings[ArSize]; // array of objects char temp[MaxLen] // temporary string storage int i; for (i = 0; i < ArSize; i++) { cout << i + 1 << ": "; cin.get(temp, MaxLen); while(cin && cin.get()!='\n') continue; if(!cin||temp[0] == '\0') // empty line? break; // i not increamented else sayings[i] = temp; // overloaded assignment } int total = i; // total # of lines read if( total > 0) { cout << "Here are your sayings:\n"; for (i = 0; i < total; i++) cout << sayings[i][0] << ": " << sayings[i] << endl; int shortest = 0; int first = 0; for(i = 1; i < total; i++) { if(sayings[i].length() < sayings[shortest].length()) shortest = i; if(sayings[i] < sayings[first]) first = i; } cout << "Shortest saying:\n" << sayings[shortest] << endl; cout << "First alphabetically:\n" << sayings[first] << endl; cout << "This program used " << String::HowMany() << " String objects. Bye.\n" } else cout << "No input! Bye.\n"; return 0; }
代码源自: C++ Primer Plus 。 小恪亲自敲写!
感悟: 如果一部书经久不衰, 一定是有它的理由的! 正如这部书, 内容细致而深刻, 全面而严谨。获益良多!此书有点儿厚,与诸君共勉。