前言
最近發(fā)現(xiàn)要學(xué)習(xí)C++來開發(fā)NDK誓篱,不得不把基礎(chǔ)的東西記錄下來,否則學(xué)的太多會混淆笼沥,廢話不多說蚪燕,開始記錄我的C++學(xué)習(xí)之旅吧
HelloWord
導(dǎo)庫
命名空間
輸出函數(shù)
#include <iostream>
//必須帶有命名空間才能使用cout等
using namespace std;
int main()
{
? ? cout << "Hello, world!" << endl;
? ? return 0;
}
命名空間
1、命名空間屬性訪問和結(jié)構(gòu)體訪問
namespace NSP_A{
? ? int a = 9;
? ? struct Student{
? ? ? ? char name[20];
? ? ? ? int age;
? ? };
}
void main(){
? ? //使用命名空間
? ? cout << NSP_A::a << endl;
? ? //使用命名空間中的結(jié)構(gòu)體
? ? using NSP_A::Student;
? ? Student t;
}
2奔浅、命名空間的嵌套
namespace NSP_B{
? ? //命名空間嵌套
? ? namespace NSP_C{
? ? ? ? int c = 90;
? ? }
}
void main(){
? ? cout << NSP_B::NSP_C::c << endl;
}
類
1馆纳、類、屬性汹桦、方法的聲明與使用
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <iostream>
#include <stdarg.h>
using namespace std;
#define PI 3.14
class MyCircle{
//屬性(共用權(quán)限訪問修飾符)
private:
? ? double r;
? ? double s;
public:
? ? void setR(double r){
? ? ? ? this->r = r;
? ? }
? ? //獲取面積
? ? double getS(){
? ? ? ? return PI * r * r;
? ? }
};
void main(){
? ? MyCircle c;
? ? c.setR(4);
? ? cout << "圓的面積:" << c.getS() << endl;
? ? system("pause");
}
2鲁驶、類的大小
類的大小只計算普通屬性的大小,其他都不包括在內(nèi)
class A{
public:
? ? int i;
? ? int j;
? ? int k;
? ? static int m;
};
class B{
public:
? ? int i;
? ? int j;
? ? int k;
? ? void myprintf(){
? ? ? ? cout << "打印" << endl;
? ? }
};
void main(){
? ? //輸出的結(jié)果都是12
? ? cout << sizeof(A) << endl;
? ? cout << sizeof(B) << endl;
}
繼承
1舞骆、繼承基本使用
class Human{
public:
? ? void say(){
? ? ? ? cout << "說話" << endl;
? ? }
protected:
? ? int age;? ?
};
class Man : public Human{
};
void main(){
? ? //子類
? ? Man m1;
? ? m1.say();
? ? //將子類賦值給父類的引用或指針
? ? Human* h_p = &m1;
? ? h_p->say();
? ? Human &h1 = m1;
? ? h1.say();
? ? //子類對象初始化父類類型的對象
? ? Human h2 = m1;
? ? h2.say();
? ? //子類對象調(diào)用父類的成員
? ? m1.Human::say();
? ? m1.Human::age = 10;
}
2钥弯、向父類構(gòu)造方法傳參
class Human{
public:
? ? Human(char* name, int age){
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? }
protected:
? ? char* name;
? ? int age;
};
class Man : public Human{
public:
? ? //給父類構(gòu)造函數(shù)傳參径荔,同時給屬性h對象賦值
? ? Man(char *brother, char *s_name, int s_age, char *h_name, int h_age) : Human(s_name, s_age), h(h_name,h_age){
? ? ? ? this->brother = brother;
? ? }
private:
? ? Human h;
};
void main(){
? ? Man m1("Hensen","HensenBoy",18,"HensenGirl",18);
}
3、多繼承的實現(xiàn)
class Person{
};
class Citizen{
};
class Student : public Person, public Citizen{
};
4脆霎、繼承間的訪問修飾符
基類中? ? ? ? 繼承方式? ? ? ? 子類中
public? ? & public繼承 = > public
public? ? & protected繼承 = > protected
public? ? & private繼承 = > private
protected? & public繼承 = > protected
protected? & protected繼承 = > protected
protected? & private繼承 = > private
private? ? & public繼承 = > 子類無權(quán)訪問
private? ? & protected繼承 = > 子類無權(quán)訪問
private? ? & private繼承 = > 子類無權(quán)訪問
5总处、繼承的二義性
virtual:表示虛繼承,不同路徑繼承來的同名成員只有一份拷貝睛蛛,解決不明確的問題
class A{
public:
? ? char* name;
};
//這里面加了virtual關(guān)鍵字
class A1 : virtual public A{
};
//這里面加了virtual關(guān)鍵字
class A2 : virtual public A{
};
class B : public A1, public A2{
};
void main(){
? ? B b;? ?
? ? //如果程序不加virtual關(guān)鍵字就會導(dǎo)致二義性鹦马,系統(tǒng)無法辨識哪個類的name屬性,會報錯
? ? b.name = "Hensen";
? ? //這里通過指定父類顯示調(diào)用是可以的
? ? b.A1::name = "Hensen";
? ? b.A2::name = "Hensen";
}
多態(tài)
1忆肾、多態(tài)的基本使用
//Plane.h文件
#pragma once
//普通飛機
class Plane{
public:
? ? virtual void fly();
? ? virtual void land();
};
//Plane.cpp文件
#include "Plane.h"
#include <iostream>
using namespace std;
void Plane::fly(){
? ? cout << "起飛" << endl;
}
void Plane::land(){
? ? cout << "著陸" << endl;
}
//Jet.h文件
#pragma once
#include "Plane.h"
//直升飛機
class Jet : public Plane{
? ? virtual void fly();
? ? virtual void land();
};
//Jet.cpp文件
#include "Jet.h"
#include <iostream>
using namespace std;
void Jet::fly(){
? ? cout << "直升飛機在原地起飛..." << endl;
}
void Jet::land(){
? ? cout << "直升飛機降落在女神的屋頂..." << endl;
}
#include "Plane.h"
#include "Jet.h"
#include "Copter.h"
//業(yè)務(wù)函數(shù)
void bizPlay(Plane& p){
? ? p.fly();
? ? p.land();
}
void main(){
? ? Plane p1;
? ? bizPlay(p1);
? ? //直升飛機
? ? Jet p2;
? ? bizPlay(p2);
}
引用
1荸频、引用的使用
void main(){
? ? int a = 10;
? ? //&是C++中的引用,引用:變量的另外一個別名难菌,共用同個地址
? ? int &b = a;
? ? cout << b << endl;
}
2试溯、引用與指針的區(qū)別
不存在空引用,引用必須連接到一塊合法的內(nèi)存郊酒。
一旦引用被初始化為一個對象遇绞,就不能被指向到另一個對象。指針可以在任何時候指向到另一個對象燎窘。
引用必須在創(chuàng)建時被初始化摹闽。指針可以在任何時間被初始化。
3褐健、引用與指針寫法上的差異
struct Teacher{
? ? char* name;
? ? int age;
};
//帶有結(jié)構(gòu)體指針的寫法
void myprint(Teacher *t){
? ? cout << t->name << "," << t->age << endl;?
? ? //(*t).name
}
//帶有結(jié)構(gòu)體引用的寫法
void myprint2(Teacher &t){
? ? cout << t.name << "," << t.age << endl;
? ? t.age = 21;
}
//指針值交換
void swap_1(int *a, int *b){
? ? int c = 0;
? ? c = *a;
? ? *a = *b;
? ? *b = c;
}
//引用值交換
void swap_2(int &a, int &b){
? ? int c = 0;
? ? c = a;
? ? a = b;
? ? b = c;
}
void main(){
? ? Teacher t;
? ? t.name = "Hensen";
? ? t.age = 20;
? ? //指針的寫法
? ? myprint(&t);
? ? //引用的寫法
? ? myprint2(t);
? ? int x = 10;
? ? int y = 20;
? ? //指針的寫法
? ? swap_1(&x, &y);
? ? //引用的寫法
? ? swap_2(x,y);
}
4付鹿、引用的作用
把引用作為參數(shù):C++支持把引用作為參數(shù)傳給函數(shù),這比傳一般的參數(shù)更安全
把引用作為返回值:可以從C++函數(shù)中返回引用蚜迅,就像返回其他數(shù)據(jù)類型一樣
5舵匾、指針引用,代替二級指針
struct Teacher{
? ? char* name;
? ? int age;
};
//引用的寫法
void getTeacher(Teacher* &p){
? ? p = (Teacher*)malloc(sizeof(Teacher));
? ? p->age = 20;
}
//二級指針的寫法谁不,原本應(yīng)該這樣寫坐梯,但是已經(jīng)被引用的寫法代替了
void getTeacher(Teacher **p){
? ? Teacher *tmp = (Teacher*)malloc(sizeof(Teacher));
? ? tmp->age = 20;
? ? *p = tmp;
}
void main(){
? ? Teacher *t = NULL;
? ? //傳遞引用的指針t,相當(dāng)于二級指針
? ? getTeacher(&t);
}
6刹帕、常引用吵血,類似于java中final
//常引用在方法中的引用
void myprint(const int &a){
? ? cout << a << endl;?
}
void main(){? ?
? ? //引用必須要有值,不能為空偷溺,下面寫法是錯誤的
? ? //const int a;
? ? //int &a = NULL;
? ? //常引用屬性使用一
? ? int a = 10, b = 9;
? ? const int &c = a;
? ? //常引用屬性使用二
? ? const int &d = 70;
}
7蹋辅、引用與指針的大小
struct Teacher{
? ? char name[20];
? ? int age;
};
void main(){
? ? Teacher t;
? ? //引用
? ? Teacher &t1 = t;
? ? //指針
? ? Teacher *p = &t;
? ? //結(jié)果是24,引用相當(dāng)于變量的別名
? ? cout << sizeof(t1) << endl;
? ? //結(jié)果是4挫掏,指針只是存放的地址
? ? cout << sizeof(p) << endl;
? ? system("pause");
}
異常
1侦另、C++異常處理,會根據(jù)拋出的異常數(shù)據(jù)類型,進(jìn)入到相應(yīng)的catch塊中
void main(){
? ? try{
? ? ? ? int age = 300;
? ? ? ? if (age > 200){
? ? ? ? ? ? throw 9.8;
? ? ? ? }
? ? }
? ? catch (int a){
? ? ? ? cout << "int異常" << endl;
? ? }
? ? catch (char* b){
? ? ? ? cout << b << endl;
? ? }
? ? catch (...){
? ? ? ? cout << "未知異常" << endl;
? ? }
}
2淋肾、向下拋出異常
void mydiv(int a, int b){
? ? if (b == 0){
? ? ? ? throw "除數(shù)為零";
? ? }
}
void func(){
? ? try{
? ? ? ? mydiv(8, 0);
? ? }
? ? catch (char* a){
? ? ? ? throw a;
? ? }
}
void main(){
? ? try{
? ? ? ? func();
? ? }
? ? catch (char* a){
? ? ? ? cout << a << endl;
? ? }
}
3硫麻、拋出對象
class MyException{
};
void mydiv(int a, int b){
? ? if (b == 0){
? ? ? ? throw MyException();
? ? ? ? //不要拋出異常指針
? ? ? ? //throw new MyException;? ? ? ?
? ? }
}
void main(){
? ? try{
? ? ? ? mydiv(8,0);
? ? }
? ? catch (MyException& e2){
? ? ? ? cout << "MyException引用" << endl;
? ? }
? ? catch (MyException* e1){
? ? ? ? cout << "MyException指針" << endl;? ? ? ?
? ? ? ? //指針的話需要手動釋放內(nèi)存
? ? ? ? delete e1;
? ? }
}
4爸邢、方法拋出異常
void mydiv(int a, int b) throw (char*, int) {
? ? if (b == 0){
? ? ? ? throw "除數(shù)為零";?
? ? }
}
5樊卓、標(biāo)準(zhǔn)異常
//需要導(dǎo)入標(biāo)準(zhǔn)異常的依賴庫
#include<stdexcept>
class NullPointerException : public exception{
public:
? ? NullPointerException(char* msg) : exception(msg){
? ? }
};
void mydiv(int a, int b){
? ? if (b > 10){
? ? ? ? throw out_of_range("超出范圍");? ?
? ? }?
? ? else if (b == NULL){
? ? ? ? throw NullPointerException("為空");
? ? }
? ? else if (b == 0){
? ? ? ? throw invalid_argument("參數(shù)不合法");
? ? }
}
void main(){
? ? try{
? ? ? ? mydiv(8,NULL);
? ? }
? ? catch (out_of_range e1){
? ? ? ? cout << e1.what() << endl;
? ? }
? ? catch (NullPointerException& e2){
? ? ? ? cout << e2.what() << endl;
? ? }
? ? catch (...){
? ? ? ? cout << "未知異常" << endl;
? ? }
}
6、外部類異常
class Err{
public:
? ? class MyException{
? ? ? ? public:MyException(){
? ? ? ? }
? ? };
};
void mydiv(int a, int b){
? ? if (b > 10){
? ? ? ? throw Err::MyException();
? ? }
}
IO流
1杠河、普通文件
#include <iostream>
#include <fstream>
void main(){
? ? char* fname = "c://dest.txt";
? ? //輸出流
? ? ofstream fout(fname);
? ? //創(chuàng)建失敗
? ? if (fout.bad()){
? ? ? ? return;
? ? }
? ? //寫入文件
? ? fout << "Hensen" << endl;
? ? //關(guān)閉輸出流
? ? fout.close();
? ? //輸入流
? ? ifstream fin(fname);
? ? //創(chuàng)建失敗
? ? if (fin.bad()){
? ? ? ? return;
? ? }
? ? char ch;
? ? //讀取數(shù)據(jù)
? ? while (fin.get(ch)){
? ? ? ? cout << ch;
? ? }
? ? //關(guān)閉輸入流
? ? fin.close();
}
2碌尔、二進(jìn)制文件
void main(){
? ? char* src = "c://src.jpg";
? ? char* dest = "c://dest.jpg";
? ? //輸入流
? ? ifstream fin(src, ios::binary);
? ? //輸出流
? ? ofstream fout(dest, ios::binary);
? ? if (fin.bad() || fout.bad()){
? ? ? ? return;
? ? }
? ? while (!fin.eof()){
? ? ? ? //讀取
? ? ? ? char buff[1024] = {0};
? ? ? ? fin.read(buff,1024);
? ? ? ? //寫入
? ? ? ? fout.write(buff,1024);
? ? }
? ? //關(guān)閉
? ? fin.close();
? ? fout.close();
}
3、C++對象的持久化
class Person
{
public:
? ? Person()
? ? {
? ? }
? ? Person(char * name, int age)
? ? {
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? }
? ? void print()
? ? {
? ? ? ? cout << name << "," << age << endl;
? ? }
private:
? ? char * name;
? ? int age;
};
void main()
{
? ? Person p1("Hensen", 22);
? ? Person p2("HensenBoy", 18);
? ? //輸出流
? ? ofstream fout("c://c_obj.data", ios::binary);
? ? fout.write((char*)(&p1), sizeof(Person));
? ? fout.write((char*)(&p2), sizeof(Person));
? ? fout.close();
? ? //輸入流
? ? ifstream fin("c://c_obj.data", ios::binary);
? ? Person tmp;
? ? fin.read((char*)(&tmp), sizeof(Person));
? ? tmp.print();
? ? fin.read((char*)(&tmp), sizeof(Person));
? ? tmp.print();
}
函數(shù)
1券敌、函數(shù)的重載
函數(shù)可以傳默認(rèn)值參數(shù)唾戚,如果調(diào)用存在參數(shù),則默認(rèn)參數(shù)會被替代
void myprint(int x, int y = 9, int z = 8){
? ? cout << x << endl;
}
//重載
void myprint(int x,bool ret){
? ? cout << x << endl;
}
void main(){
? ? myprint(20);
? ? //覆蓋默認(rèn)參數(shù)的9和8
? ? myprint(20,10,5);
}
2待诅、可變參數(shù)函數(shù)
void func(int i,...)
{
? ? //可變參數(shù)指針
? ? va_list args_p;
? ? //可變參數(shù)設(shè)置開始位置
? ? //i表示可變參數(shù)的前一位參數(shù)叹坦,從i開始,后面的就是可變參數(shù)
? ? va_start(args_p,i);
? ? int a = va_arg(args_p,int);
? ? char b = va_arg(args_p, char);
? ? int c = va_arg(args_p, int);
? ? cout << a << endl;
? ? cout << b << endl;
? ? cout << c << endl;
? ? //可變參數(shù)設(shè)置結(jié)束
? ? va_end(args_p);
}
void main(){
? ? //使用
? ? func(9,20,'b',30);
}
可變參數(shù)也可以循環(huán)讀取卑雁,但是必須保證所有數(shù)大于0使用
void func(int i,...)
{
? ? va_list args_p;
? ? //開始
? ? va_start(args_p,i);
? ? int value;
? ? while (1){
? ? ? ? value = va_arg(args_p,int);
? ? ? ? if (value <= 0){
? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? cout << value << endl;
? ? }
? ? //結(jié)束
? ? va_end(args_p);
}
3募书、靜態(tài)屬性和方法
class Teacher{
public:
? ? char* name;
? ? //計數(shù)器
? ? static int total;
public:
? ? Teacher(char* name){
? ? ? ? this->name = name;? ? ?
? ? ? ? cout << "Teacher有參構(gòu)造函數(shù)" << endl;
? ? }
? ? void setName(char* name){
? ? ? ? this->name = name;
? ? }
? ? char* getName(){
? ? ? ? return this->name;
? ? }
? ? //計數(shù),靜態(tài)函數(shù)
? ? static void count(){
? ? ? ? total++;? ? ? ?
? ? ? ? cout << total << endl;
? ? }
};
//靜態(tài)屬性初始化賦值
int Teacher::total = 9;
void main(){
? ? //靜態(tài)變量的使用
? ? Teacher::total++;
? ? cout << Teacher::total << endl;
? ? //靜態(tài)方法的使用一
? ? Teacher::count();
? ? //靜態(tài)方法的使用二
? ? Teacher t1("Hensen");
? ? t1.count();
}
4测蹲、常量對象和常函數(shù)
class Teacher{
private:
? ? char* name;
? ? int age;
public:
? ? Teacher(char* name,int age){
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? ? ? cout << "Teacher有參構(gòu)造函數(shù)" << endl;
? ? }
? ? //常函數(shù)莹捡,當(dāng)前對象不能被修改,防止數(shù)據(jù)成員被非法訪問
? ? void myprint() const{
? ? ? ? //不能通過this->name修改值
? ? ? ? cout << this->name << "," << this->age << endl;
? ? }
? ? void myprint2(){? ? ? ?
? ? ? ? cout << this->name << "," << this->age << endl;? ?
? ? }
};
void main(){
? ? //普通對象
? ? Teacher t1("Hensen",20);
? ? //常對象
? ? const Teacher t2("rose", 18);
? ? //普通對象可以調(diào)用常函數(shù)扣甲,也可以調(diào)用普通函數(shù)
? ? t1.myprint();
? ? //t2.myprint2(); 常量對象只能調(diào)用常量函數(shù)篮赢,不能調(diào)用非常量函數(shù)
? ? t2.myprint();
}
虛函數(shù)
1、純虛函數(shù)(類似于抽象類)
當(dāng)一個類具有一個純虛函數(shù)琉挖,這個類就是抽象類
抽象類不能實例化對象
子類繼承抽象類启泣,必須要實現(xiàn)純虛函數(shù),如果沒有示辈,子類也是抽象類
class Shape{
public:
? ? //純虛函數(shù)
? ? virtual void sayArea() = 0;
? ? void print(){
? ? ? ? cout << "hi" << endl;
? ? }
};
class Circle : public Shape{
public:
? ? Circle(int r){
? ? ? ? this->r = r;
? ? }
? ? //必須實現(xiàn)純虛函數(shù)
? ? void sayArea(){
? ? ? ? cout << "圓的面積:" << (3.14 * r * r) << endl;
? ? }
private:
? ? int r;
};
void main(){
? ? Circle c(10);
}
2寥茫、接口
//接口(只是邏輯上的劃分,語法上跟抽象類的寫法沒有區(qū)別)
class Drawble{
? ? virtual void draw();
};
模板函數(shù)
1顽耳、模板函數(shù)使用坠敷,相當(dāng)于泛型
void myswap(int& a,int& b){
? ? int tmp = 0;
? ? tmp = a;
? ? a = b;
? ? b = tmp;
}
void myswap(char& a, char& b){
? ? char tmp = 0;
? ? tmp = a;
? ? a = b;
? ? b = tmp;
}
//可以將上面的函數(shù)抽取成模板函數(shù)
template <typename T>
void myswap(T& a, T& b){
? ? T tmp = 0;
? ? tmp = a;
? ? a = b;
? ? b = tmp;
}
void main(){
? ? int a = 10, b = 20;
? ? //使用時,根據(jù)實際類型射富,指定模板類型
? ? myswap<int>(a,b);
}
模板類
1膝迎、模板類使用
template<class T>
class A{
public:
? ? A(T a){
? ? ? ? this->a = a;
? ? }
protected:
? ? T a;
};
void main(){
? ? //實例化模板類對象
? ? A<int> a(6);
}
2、普通類繼承模板類
class B : public A<int>{
public:
? ? B(int a,int b) : A<int>(a){
? ? ? ? this->b = b;
? ? }
private:
? ? int b;
};
3胰耗、模板類繼承模板類
template <class T>
class C : public A<T>{
public:
? ? C(T c, T a) : A<T>(a){
? ? ? ? this->c = c;
? ? }
protected:
? ? T c;
};
構(gòu)造函數(shù)
函數(shù)分為三種
構(gòu)造函數(shù)
析構(gòu)函數(shù)
拷貝函數(shù)
1限次、無參構(gòu)造函數(shù)和有參構(gòu)造函數(shù)
class Teacher{
private:
? ? char *name;
? ? int age;
public:
? ? //無參構(gòu)造函數(shù)(無參構(gòu)造函數(shù)會覆蓋默認(rèn)的無參構(gòu)造函數(shù))
? ? Teacher(){
? ? ? ? cout << "無參構(gòu)造函數(shù)" << endl;
? ? }
? ? //有參構(gòu)造函數(shù)會覆蓋默認(rèn)的構(gòu)造函數(shù)
? ? Teacher(char *name, int age){
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? ? ? cout << "有參構(gòu)造函數(shù)" << endl;
? ? }?
};
void main(){
? ? Teacher t1("Hensen",20);
? ? //另外一種調(diào)用方式
? ? Teacher t2 = Teacher("Hensen",21);
}
2、析構(gòu)函數(shù)
class Teacher{
private:
? ? char *name;
? ? int age;
public:
? ? //無參構(gòu)造函數(shù)賦默認(rèn)值
? ? Teacher(){
? ? ? ? this->name = (char*)malloc(100);
? ? ? ? strcpy(name,"Hensen");
? ? ? ? age = 20;
? ? ? ? cout << "無參構(gòu)造函數(shù)" << endl;
? ? }
? ? //析構(gòu)函數(shù)寫法
? ? //當(dāng)對象要被系統(tǒng)釋放時,析構(gòu)函數(shù)被調(diào)用卖漫,一般使用于程序的善后工作
? ? ~Teacher(){
? ? ? ? cout << "析構(gòu)" << endl;
? ? ? ? //釋放內(nèi)存
? ? ? ? free(this->name);
? ? }
};
void func(){
? ? Teacher t1;
}
void main(){
? ? func();
}
3费尽、拷貝構(gòu)造函數(shù)
class Teacher{
private:
? ? char *name;
? ? int age;
public:
? ? Teacher(char *name, int age){
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? ? ? cout << "有參構(gòu)造函數(shù)" << endl;
? ? }
? ? //拷貝構(gòu)造函數(shù)寫法
? ? //默認(rèn)拷貝構(gòu)造函數(shù),就是值拷貝
? ? Teacher(const Teacher &obj){
? ? ? ? this->name = obj.name;
? ? ? ? this->age = obj.age;
? ? ? ? cout << "拷貝構(gòu)造函數(shù)" << endl;
? ? }
? ? void myprint(){
? ? ? ? cout << name << "," << age << endl;
? ? }
};
Teacher func1(Teacher t){
? ? t.myprint();
? ? return t;
}
void main(){
? ? Teacher t1("rose",20);
? ? func1(t1);
? ? //這里不會調(diào)用拷貝函數(shù)的
? ? //Teacher t1 ;
? ? //Teacher t2;
? ? //t1 = t2;
}
拷貝構(gòu)造函數(shù)被調(diào)用的場景:
聲明時賦值:Teacher t2 = t1;
作為參數(shù)傳入羊始,實參給形參賦值:上面的寫法就是
作為函數(shù)返回值返回旱幼,給變量初始化賦值:Teacher t3 = func1(t1);
4、拷貝函數(shù)的問題突委,淺拷貝(值拷貝)問題
class Teacher{
private:
? ? char *name;
? ? int age;
public:
? ? Teacher(char *name, int age){
? ? ? ? this->name = (char*)malloc(100);
? ? ? ? strcpy(this->name,name);
? ? ? ? this->age = age;
? ? ? ? cout << "有參構(gòu)造函數(shù)" << endl;
? ? }?
? ? ~Teacher(){
? ? ? ? cout << "析構(gòu)" << endl;
? ? ? ? //釋放內(nèi)存
? ? ? ? free(this->name);
? ? }
? ? void myprint(){
? ? ? ? cout << name << "," << age << endl;
? ? }
};
void func(){
? ? Teacher t1("rose", 20);
? ? Teacher t2 = t1;
}
void main(){
? ? func();
}
這樣的使用柏卤,會導(dǎo)致t1和t2都調(diào)用析構(gòu)函數(shù),導(dǎo)致同一份內(nèi)存被釋放兩次匀油,結(jié)果程序會報錯
5缘缚、解決淺拷貝問題,使用深拷貝
深拷貝很好理解敌蚜,其實就是將參數(shù)進(jìn)行再一次分配內(nèi)存桥滨,這樣的程序就不會出錯
class Teacher{
private:
? ? char *name;
? ? int age;
public:
? ? Teacher(char *name, int age){
? ? ? ? int len = strlen(name);
? ? ? ? this->name = (char*)malloc(len+1);
? ? ? ? strcpy(this->name, name);
? ? ? ? this->age = age;
? ? ? ? cout << "有參構(gòu)造函數(shù)" << endl;
? ? }
? ? ~Teacher(){
? ? ? ? cout << "析構(gòu)" << endl;
? ? ? ? //釋放內(nèi)存
? ? ? ? free(this->name);
? ? }
? ? //深拷貝
? ? Teacher(const Teacher &obj){
? ? ? ? int len = strlen(obj.name);
? ? ? ? this->name = (char*)malloc(len+1);
? ? ? ? strcpy(this->name,obj.name);
? ? ? ? this->age = obj.age;
? ? }
? ? void myprint(){
? ? ? ? cout << name << "," << age << endl;
? ? }
};
void func(){
? ? Teacher t1("rose", 20);
? ? Teacher t2 = t1;
}
void main(){
? ? func();
}
6、構(gòu)造函數(shù)初始化屬性寫法
class Student{
private:
? ? int id;
? ? //屬性對象可以直接的初始化
? ? //Teacher t = Teacher("miss cang");
? ? Teacher t1;
? ? Teacher t2;
public:
? ? //屬性對象可以在這里間接的初始化
? ? Student(int id,char *t1_n, char* t2_n) : t1(t1_n), t2(t2_n){
? ? ? ? this->id = id;
? ? ? ? cout << "Student有參構(gòu)造函數(shù)" << endl;
? ? }
? ? void myprint(){
? ? ? ? cout << id << "," << t1.getName() <<"," << t2.getName() << endl;
? ? }
? ? ~Student(){
? ? ? ? cout << "Student析構(gòu)函數(shù)" << endl;
? ? }
};
void func(){
? ? Student s1(10, "miss xu", "mrs li");
? ? Student s2(20, "miss ya", "mrs wang");
}
void main(){
? ? func();
}
7弛车、析構(gòu)函數(shù)和構(gòu)造函數(shù)的執(zhí)行順序
class Human{
public:
? ? Human(char* name, int age){
? ? ? ? this->name = name;
? ? ? ? this->age = age;
? ? ? ? cout << "Human 構(gòu)造函數(shù)" << endl;
? ? }
? ? ~Human(){
? ? ? ? cout << "Human 析構(gòu)函數(shù)" << endl;
? ? }
protected:
? ? char* name;
? ? int age;
};
class Man : public Human{
public:
? ? //給父類構(gòu)造函數(shù)傳參齐媒,同時給屬性對象賦值
? ? Man(char *brother, char *s_name, int s_age) : Human(s_name, s_age){
? ? ? ? this->brother = brother;
? ? ? ? cout << "Man 構(gòu)造函數(shù)" << endl;
? ? }
? ? ~Man(){
? ? ? ? cout << "Man 析構(gòu)函數(shù)" << endl;
? ? }
private:
? ? char* brother;
};
void func(){
? ? Man m1("Hensen", "HensenBoy", 18);
}
void main(){
? ? func();
}
輸出結(jié)果是:父類構(gòu)造函數(shù)先調(diào)用,子類的析構(gòu)函數(shù)先調(diào)用
Human構(gòu)造函數(shù)
Man構(gòu)造函數(shù)
Man析構(gòu)函數(shù)
Human析構(gòu)函數(shù)
友元函數(shù)
友元函數(shù):使得類的私有屬性可以通過友元函數(shù)進(jìn)行訪問
1帅韧、友元函數(shù)
class A{
? ? //友元函數(shù)聲明
? ? friend void modify_i(A *p, int a);
private:
? ? int i;
public:
? ? A(int i){
? ? ? ? this->i = i;
? ? }
? ? void myprint(){
? ? ? ? cout << i << endl;
? ? }?
};
//友元函數(shù)的實現(xiàn)
void modify_i(A *p, int a){
? ? p->i = a;
}
void main(){
? ? A* a = new A(10);
? ? a->myprint();
? ? modify_i(a,20);
? ? a->myprint();
}
2里初、友元類
class A{? ? ? ?
? ? //友元類聲明,表示B這個友元類可以訪問A類的任何成員
? ? friend class B;
private:
? ? int i;
public:
? ? A(int i){
? ? ? ? this->i = i;
? ? }
? ? void myprint(){
? ? ? ? cout << i << endl;
? ? }?
};
class B{
private:
? ? A a;
public:
? ? void accessAny(){
? ? ? ? a.i = 30;? ? ?
? ? }
};
類型轉(zhuǎn)換
C++類型轉(zhuǎn)換分為4種
static_cast:類型轉(zhuǎn)換忽舟,意圖明顯双妨,增加可閱讀性
const_cast:常量的轉(zhuǎn)換,將常量取出叮阅,并可以對常量進(jìn)行修改
dynamic_cast:子類類型轉(zhuǎn)為父類類型
reinterpret_cast:函數(shù)指針轉(zhuǎn)型刁品,不具備移植性
1、static_cast的使用
void* func(int type){?
? ? switch (type){
? ? ? ? case 1: {
? ? ? ? ? ? int i = 9;
? ? ? ? ? ? return &i;
? ? ? ? }
? ? ? ? case 2: {
? ? ? ? ? ? int a = 'X';
? ? ? ? ? ? return &a;
? ? ? ? }
? ? ? ? default:{
? ? ? ? ? ? return NULL;
? ? ? ? }
? ? }?
}
void func2(char* c_p){
? ? cout << *c_p << endl;
}
void main(){? ?
? ? int i = 8;
? ? double d = 9.5;
? ? i = static_cast<int>(d);
? ? //C的寫法
? ? //char* c_p = (char*)func(2);
? ? //C++的寫法
? ? char* c_p = static_cast<char*>(func(2));
? ? //C的寫法
? ? //func2((char*)(func(2)));
? ? //C++的寫法
? ? func2(static_cast<char*>(func(2)));
}
2浩姥、const_cast的使用
void func(const char c[]){
? ? //C的寫法
? ? //char* c_p = (char*)c;
? ? //c_p[1] = 'X';
? ? //C++的寫法挑随,提高了可讀性
? ? char* c_p = const_cast<char*>(c);
? ? c_p[1] = 'Y';
? ? cout << c << endl;
}
void main(){
? ? char c[] = "hello";
? ? func(c);
}
3、dynamic_cast的使用
class Person{
public:
? ? virtual void print(){
? ? ? ? cout << "人" << endl;
? ? }
};
class Man : public Person{
public:
? ? void print(){
? ? ? ? cout << "男人" << endl;
? ? }
? ? void chasing(){
? ? ? ? cout << "泡妞" << endl;
? ? }
};
class Woman : public Person{
public:
? ? void print(){
? ? ? ? cout << "女人" << endl;
? ? }
? ? void carebaby(){
? ? ? ? cout << "生孩子" << endl;
? ? }
};
void func(Person* obj){
? ? //C的寫法勒叠,C只會調(diào)用傳遞過來的對象方法兜挨,并不知道轉(zhuǎn)型失敗這回事
? ? //Man* m = (Man*)obj;
? ? //m->print();
? ? //C++的寫法,dynamic_cast如果轉(zhuǎn)型失敗眯分,會返回NULL拌汇,保證了代碼的安全性
? ? Man* m = dynamic_cast<Man*>(obj);?
? ? if (m != NULL){
? ? ? ? m->chasing();
? ? }
? ? Woman* w = dynamic_cast<Woman*>(obj);
? ? if (w != NULL){
? ? ? ? w->carebaby();
? ? }
}
void main(){
? ? Woman w1;
? ? Person *p1 = &w1;
? ? //輸出結(jié)果是生孩子
? ? func(p1);
}
4、reinterpret_cast的使用
void func1(){
? ? cout << "func1" << endl;
}
char* func2(){
? ? cout << "func2" << endl;
? ? return "abc";
}
typedef void(*f_p)();
void main(){
? ? //函數(shù)指針數(shù)組
? ? f_p f_array[6];
? ? f_array[0] = func1;
? ? //C的寫法
? ? //f_array[1] = (f_p)(func2);
? ? //C++方式
? ? f_array[1] = reinterpret_cast<f_p>(func2);
? ? //調(diào)用方法
? ? f_array[1]();
}
內(nèi)存分配
1弊决、C++ 通過new(delete)動態(tài)內(nèi)存分配
使用new的方式:和malloc一樣的功能噪舀,但是會自動調(diào)用構(gòu)造函數(shù)
使用delete的方式:和free一樣的功能魁淳,但是會自動調(diào)用析構(gòu)函數(shù)
指針的malloc、free可以和new与倡、delete互相摻雜使用界逛,但是malloc、free不會調(diào)用構(gòu)造函數(shù)和析構(gòu)函數(shù)
class Teacher{
private:
? ? char* name;
public:
? ? Teacher(char* name){
? ? ? ? this->name = name;
? ? ? ? cout << "Teacher有參構(gòu)造函數(shù)" << endl;
? ? }
? ? ~Teacher(){
? ? ? ? cout << "Teacher析構(gòu)函數(shù)" << endl;
? ? }
? ? void setName(char* name){
? ? ? ? this->name = name;
? ? }
? ? char* getName(){
? ? ? ? return this->name;
? ? }
};
void func(){
? ? Teacher *t1 = new Teacher("jack");
? ? cout << t1->getName() << endl;
? ? delete t1;
}
void main(){
? ? func();
}
運算符重載
1纺座、運算符重載的寫法一
class Point{
public:
? ? int x;
? ? int y;
public:
? ? Point(int x = 0, int y = 0){
? ? ? ? this->x = x;
? ? ? ? this->y = y;
? ? }
? ? void myprint(){
? ? ? ? cout << x << "," << y << endl;
? ? }
};
//重載+號
Point operator+(Point &p1, Point &p2){
? ? Point tmp(p1.x + p2.x, p1.y + p2.y);
? ? return tmp;
}
//重載-號
Point operator-(Point &p1, Point &p2){
? ? Point tmp(p1.x - p2.x, p1.y - p2.y);
? ? return tmp;
}
void main(){
? ? Point p1(10,20);
? ? Point p2(20,10);
? ? Point p3 = p1 + p2;
? ? //輸出結(jié)果30息拜,30
? ? p3.myprint();
}
2、運算符重載的寫法二
class Point{
public:
? ? int x;
? ? int y;
public:
? ? Point(int x = 0, int y = 0){
? ? ? ? this->x = x;
? ? ? ? this->y = y;
? ? }
? ? //成員函數(shù)比驻,運算符重載
? ? Point operator+(Point &p2){
? ? ? ? Point tmp(this->x + p2.x, this->y + p2.y);
? ? ? ? return tmp;
? ? }
? ? void myprint(){
? ? ? ? cout << x << "," << y << endl;
? ? }
};
void main(){
? ? Point p1(10, 20);
? ? Point p2(20, 10);
? ? //運算符的重載该溯,本質(zhì)還是函數(shù)調(diào)用
? ? //p1.operator+(p2)
? ? Point p3 = p1 + p2;
? ? p3.myprint();
}
3、通過友元函數(shù)和運算符重載訪問私有變量
class Point{
? ? friend Point operator+(Point &p1, Point &p2);
private:
? ? int x;
? ? int y;
public:
? ? Point(int x = 0, int y = 0){
? ? ? ? this->x = x;
? ? ? ? this->y = y;
? ? }?
? ? void myprint(){
? ? ? ? cout << x << "," << y << endl;
? ? }
};
Point operator+(Point &p1, Point &p2){
? ? Point tmp(p1.x + p2.x, p1.y + p2.y);
? ? return tmp;
}
void main(){
? ? Point p1(10, 20);
? ? Point p2(20, 10);
? ? //運算符的重載别惦,本質(zhì)還是函數(shù)調(diào)用
? ? //p1.operator+(p2)
? ? Point p3 = p1 + p2;
? ? p3.myprint();
}
其他
1、布爾類型(bool)
布爾類型的值大于0的都為true夫椭,布爾類型的值小于等于0的都為false
2掸掸、三目運算符
三目運算符可以作為參數(shù)進(jìn)行賦值
int a = 10, b = 20;
((a > b) ? a : b) = 30;
3、指針常量與常量指針
指針常量(int *const p):指針的常量蹭秋,表示不可以修改p的地址扰付,但是可以修改p的內(nèi)容
常量指針(const int *p):指向常量的指針,表示不可以修改p的內(nèi)容仁讨,但是可以修改p的地址
4羽莺、指針函數(shù)與函數(shù)指針
指針函數(shù)(int *fun(x,y)):指向指針的函數(shù),其實可以說是返回指針的函數(shù)
函數(shù)指針(int (*fun)(x,y);funa = fun;funb = fun;):指向函數(shù)的指針
加C/C++學(xué)習(xí)交流QQ群728483370洞豁,領(lǐng)取項目開發(fā)和新手教學(xué)等視頻