1.面向對象
<1>直接定義類
class People { public: void sayHello() { printf("hello c oop \n"); } };
People * p = new People(); p->sayHello();
<2>使用頭文件定義
Ml.h
#ifndef ML_H_ #define ML_H_ namespace cjyn { // 命名空間 class Ml { public: void sayHello(); }; } #endif /* ML_H_ */
Ml.cpp
#include "Ml.h" #include <iostream> #include <stdio.h> namespace cjyn { void Ml::sayHello() { // 返回類型 類名::方法名 printf("hello cpp"); } }
main.cpp 調用
#include <iostream> #include "Ml.h" #include <stdio.h> using namespace cjyn; int main(int argc, const char* argv[]) { cjyn::Ml *ml = new cjyn::Ml(); ml->sayHello(); delete ml; // 釋放對象,如同C中的free }
補充:如果沒有引入using namespace cyjn,則在申明類的時候需要使用(命名空間::類名)的方式,如果引入了命名空間,則上面的申明可以直接使用類名而不需要使用命名空間;
2.類的繼承(People->Man)
People.cpp
#include "People.h" #include <iostream> #include <stdio.h> void People::sayHello() { printf("hello cpp"); } int People::getAge() { return this->age; } People::People(int age) { this->age = age; } People::People() { this->age = 12; }
People.h
#ifndef ML_H_ #define ML_H_ class People { private: int age; public: People(); People(int age); void sayHello(); void setAge(); int getAge(); }; #endif /* ML_H_ */
子類Man
Man.cpp
#include "Man.h"
Man.h
#ifndef MAN_H_ #define MAN_H_ #include "People.h" class Man: public People { // public 表示從父類繼承下來的成員變量是public的 public: }; #endif /* MAN_H_ */
main.cpp
int main(int argc, const char* argv[]) { Man *m = new Man(); m->sayHello(); //hello cpp delete m; }
3.引用父類方法
<1>.構造方法
Man.h
#ifndef MAN_H_ #define MAN_H_ #include "People.h" class Man: public People { // public 表示從父類繼承下來的成員變量是public的 public: Man(int age); void sayHello(); }; #endif /* MAN_H_ */
Man.cpp
Man::Man(int age) : People(age) { // 想要執行父類的構造方法只需要在子類構造方法之後加冒號並且調用父類構造方法即可 }
<2>.其他方法調用
Man.cpp
Man::Man(int age) : People(age) { People::sayHello(); // @1 } void Man::sayHello() { printf("man say hello cpp\n"); }
Man.h
class Man: public People { // public 表示從父類繼承下來的成員變量是public的 public: Man(int age); void sayHello(); }; #endif /* MAN_H_ */
main.cpp
int main(int argc, const char* argv[]) { Man *m = new Man(34); printf("age %d \n", m->getAge()); m->sayHello(); // 調用man的sayHello m->People::sayHello(); // 調用People的sayHello @2 delete m; }
父類普通方法的調用之需要在方法名前加(類名::方法名),有兩種調用方式@1,@2;
4.面向對象特點
<1>.虛函數、純虛函數、純虛類
class People { private: int age; public: People(); People(int age); // 虛函數:定義為虛函數之後就可以在運行的時候動態加載相應的方法(相當於java中多態); virtual void sayHello(); // 純虛函數,相當於java中的抽象方法;對應的類就是抽象類 virtual void eat()=0; void setAge(); int getAge(); }; #endif /* ML_H_ */
純虛類就是類中所有方法都是純虛函數,相當於java中的接口;
虛函數和純虛函數分別由子類去重寫(可重寫可不重寫)和實現(子類必須進行實現);
Man.h
class Man: public People { public: Man(int age); virtual void sayHello(); virtual void eat(); }; #endif /* MAN_H_ */
Man.cpp
Man::Man(int age) : People(age) { // 調用父類構造方法 } void Man::sayHello() { printf("man say hello cpp\n"); } void Man::eat(){ printf("man eat\n"); }
5.操作符重載
class Point { private: int x, y; public: Point(int x, int y) { this->x = x; this->y = y; } void add(Point p) { this->x += p.x; this->y += p.y; } void operator +=(Point p) { add(p); } int getX() { return this->x; } int getY() { return this->y; } };
實例:
int main(int argc, const char* argv[]) { Point p(10, 10); std::cout << p.getX() << "\n"; p += Point(12, 12); std::cout << p.getX() << "\n"; Point *pp = new Point(5, 5); (*pp) += Point(4, 4); std::cout << pp->getX() << "\n"; }
上述代碼輸出結果為:10,22,9;
<2>.操作符重載之偽函數
偽函數就是把一個類當作一個方法來調用,下面直接看例子
class Point { public: void operator ()() { std::cout << "hello point" << "\n"; } };
使用(這種方式的有點在於比如把類當作一個參數傳遞)
int main(int argc, const char* argv[]) { Point p; p(); // 輸出hello point }
6.函數指針
C++中函數指針和C語言中函數指針其實比較類似,下面是C語言中的兩種定義方法
接著來看C++中函數指針的定義
class Object { public: void (Object::*sayHi)(); };
class Object; typedef void (Object::*SayHi)(); class Object { public: SayHi sayHi; };
通過上面的例子不難看出,都是返回類型+(指針名稱定義)+(參數) ,不過在C++中,需要定義函數指針所在的類,在上面即是限定指針為Object的成員或者Object子類的成員;
下面看一個例子:編寫一個類繼承自Object,並且給sayHi指針賦值;
class Hello : public Object { public: Hello(){ //sayHi = (void(Object::*)())(&Hello::helloSayHi); 將Hello本身的helloSayHi方法賦予sayHi;使用@1方式定義指針 //sayHi = (SayHi)(&Hello::helloSayHi); 將Hello的helloSzyHi方法賦予sayHi,使用@2方式定義指針 //(this->*sayHi)(); // 執行sayHi指針; } void helloSayHi(){ printf("hello say hi\n"); } };
再來看一個例子(延遲執行):
class Object; typedef void (Object::*CallaterHandler)(); // 定義一個指針,該指針所屬類為Object類; #define CH(fp) (CallaterHandler)(&fp) // 取fp的地址,強制轉換為CallaterHandler; void threadFunc(Object *obj,CallaterHandler handler,int delay){ // _Thrd_sleep(d); // thread sleep (obj->*handler)(); // 執行handler指針 } void callater(Object *obj,CallaterHandler handler,int delay){ std::thread t(threadFunc,obj,handler,delay); t.join(); } class Object {}; class Hello : public Object { public: Hello(){ //callater(this,(CallaterHandler)(&Hello::helloSayHi),3); callater(this,CH(Hello::helloSayHi),3); } void helloSayHi(){ printf("hello say hi\n"); } };
7.引用
先來看一個例子
class PP { public: PP(int x) { this->x = x; } void add(PP p) { this->x += p.getX(); } int getX() { return this->x; } private: int x; };
上面的add方法傳入一個PP對象,在執行相加方法時,會對傳入的對象進行內存的拷貝,事實上這樣的效率不高,為了防止內存的拷貝,可以把add方法更改為
add(PP &p) // &表示取地址
當然,這樣的實現完全可以直接通過指針來代替;
8.有元類
在C++中,默認沒家修飾符的字段為private,但是有時候需要把特定的字段公開給某一個類,這時候就需要用到有元類;
class A { friend class B; // 通過這樣定義,就可以在B類中訪問到num private: int num; public: A() { num = 10; } }; class B { public: B() { A a; printf("%d", a.num); } };
9.集合|容器
int main(int argc, const char* argv[]) { std::list<std::string> l; // 需要導入list l.push_back("hello"); l.push_back("spring"); std::list<std::string>::iterator it = l.begin(); for (; it != l.end(); it++) { std::cout << *it << "\n"; } map<string, string> m; // 需要導入map m.insert(pair<string, string>("key1", "value1")); m.insert(pair<string, string>("key2", "value2")); // m["key1"] = "value1+"; // cout << m.at("key1"); return 0; }
上面的代碼輸出結果為:hello spring value1+
10.字符串
#include <iostream> #include <string> #include <sstream> using namespace std; int main(int argc, const char* argv[]) { string s; s += "hello "; s += "string"; cout << s << "\n"; stringstream ss; ss << "hello"; ss << 23; ss << "spring" << 25; cout << ss.str()<<"\n"; return 0; }
11.文件操作
#include <iostream> #include <string> #include <sstream> #include <fstream> using namespace std; int main(int argc, const char* argv[]) { // ofstream of("data.txt"); // of << "hello cpp \n"; // of.close(); ifstream inf("data.txt"); char c; inf >> c; cout << c << "\n"; // 讀取第一個字符 stringbuf sb; inf >> &sb; cout << sb.str() << "\n"; // 讀取全部字符 return 0; }