C++基础


C++基础

本文收录了黑马程序员C++网课的部分代码,可供参考。

指针

指针的基本概念

//可以通过指针间接访问内存
//内存编号是从0开始记录的 一般会用十六进制数字表示
//可以利用指针变量保存地址
//语法:数据类型*变量名;
#include<iostream>
using namespace std;

int main() {

    //定义指针
    int a = 10;
    int * p1;
    //让指针记录变量a的地址
    p1= &a;//&为取址符号
    cout << "a的地址为:" << &a << endl;
    cout << "指针p为:" << p1<<endl;

    //使用指针
    //可以通过解引用的方式来找到指针指向的内存
    //指针前加*代表解引用 找到指针指向的内存中的数据
    *p1 = 1000;
    cout << "a=" << a << endl;
    cout << "*p=" << *p1 << endl;

    system("pause");
    return 0;
}

指针所占内存空间

//在32位操作系统下 占用4个字节空间 64位操作系统下 占用8个字节空间
#include<iostream>
using namespace std;

int main() {
    int a = 10;
    /*int* p;
    p = &a;*/
    int* p2 = &a;//创建指针

    // 以下全部打印 8
    cout << "sizeof int * =" << sizeof(int*) << endl;
    cout << "sizeof float * =" << sizeof(float*) << endl;
    cout << "sizeof double * =" << sizeof(double*) << endl;
    cout << "sizeof char * =" << sizeof(char*) << endl;


    system("pause");
    return 0;
}

空指针

//空指针:指针变量指向内存中编号为0的空间
//用途:初始化指针变量
//注意:空指针指向的内存是不可以访问的
#include<iostream>
using namespace std;

int main() {
    //空指针
    //用于给指针变量进行初始化且不可以进行访问
    //0~255之间的内存编号是系统占用的 因此不可以访问
    int* p3=NULL;
    *p3 = 100;    //不可访问,强行运行会报错
    system("pause");
    return 0;
}

野指针

//指针变量指向非法的内存空间
#include<iostream>
using namespace std;

int main() {
    //野指针
    //在程序中 尽量避免出现野指针
    int* p4 = (int*)0x1100;

    cout << *p4 << endl;    //强行访问会出错

    system("pause");
    return 0;
}
//空指针和野指针都不是我们申请的空间 因此不要访问 访问就会出错

const修饰指针

/*const修饰指针有三种情况
const修饰指针——常量(的)指针 指针的指向(p=&x)可以修改 但是指针指向的值(指向的内存的数据)(*p)不可以改
(const int * p=&a;)
const修饰常量——指针(是)常量 指针的指向不可以修改 但是指针指向的值可以改
(int * const p=&a;)
const既修饰指针 又修饰常量 指针的指向和指向的值都不可以改
(const int * const p=&a;)
*/
#include<iostream>
using namespace std;

int main() {
    ////const修饰指针
    //int a = 10;
    //int b = 10;

    //int* p= &a;
    //const int* p = &a;//常量指针 *p指针指向的值不能改 指针指向可以改
    //p = &b;

    ////const修饰常量
    //int* p = &a;
    //int* const p = &a;//指针指向不可以改 指针指向的值*p可以改
    //*p = 100;

    ////const修饰指针和常量
    //int* p = &a;
    ////指针指向和指针指向的值都不可以改
    system("pause");
    return 0;
}

程序的内存模型

程序执行时,将内存大方向分为4个区域:

  • 代码区:存放函数体的二进制代码,有操作系统进行管理。

  • 全局区:存放全局变量和静态变量以及常量(字符串常量,const修饰的全局变量)。

  • 栈区:由编译器自动分配释放,存放函数的参数值,局部变量等。

  • 堆区:由程序员分配和释放,若程序员不释放,程序结束时由操作系统回收。

不同区域存放的数据,赋予不同的生命周期,给我们更大的灵活编程。

引用

引用做函数返回值

//注意不要返回局部变量引用
//用法:函数调用作为左值
#include<iostream>
using namespace std;
int&  test01() {
    int a = 10;//存放在栈区,test01执行后就被释放掉了
    return a;
}
int& test02() {
    static int a = 10;//静态变量存放在全局区,全局区上的数据在程序结束后系统释放
    return a;
}
int main() {
    int& ref = test02();//这里ref可以理解为test02的别名,且test02是a的别名
    cout << ref << endl;    //10
    test02() = 100;//函数调用作为左值
    cout << ref << endl;    //100
    return 0;
}

引用的本质

引用的本质是在c++中实现一个指针常量。
int *const p; p=&x不可以更改,*p可以更改。

所以引用一旦初始化之后,就不可更改。

int &ref = a; ---> int *const p = &a;

ref = 20 ---> *p = 20;

常量引用

//常量引用主要用来修饰形参,防止误操作
//在函数形参列表中,可以加const修饰形参,防止形参改变实参
#include<iostream>
using namespace std;
void showValue(const int& val) {
    //val = 1000;
    cout << "val=" << val << endl;
}
int main() {
    /*  int a = 10;
    //int& ref = 10;这行代码是错误的
    const int& ref = 10;//加上const之后,编译器将代码修改为 int temp =10; const int& ref = temp;
    //加入const之后ref不可修改了  */
    int a = 100;
    showValue(a);
    cout << a << endl;
    return 0;
}

函数高级

函数的默认参数

//某一个位置有默认值,则从这个位置开始,从左往右,都必须有默认值
//如果函数声明有默认值,那么函数实现的时候就不能有默认值
#include<iostream>
using namespace std;
int func(int a, int b=20, int c=30) {
    return a + b + c;
}
int func01(int a, int b=10);
int func01(int a, int b) {//声明和实现只能有一个地方有默认值
    return a + b;
}
int main() {
    int a = 10,d=0;
    d = func(a,40);//自己传入数据就用自己的,否则就用默认的
    cout << d << endl;
    return 0;
}

函数的占位参数

#include<iostream>
using namespace std;
void func(int a,int =10) {//后面的int起到占位的作用,占位参数后面也可以跟一个数据
    cout << "this is function" << endl;
}
int main2() {
    func(1,2);
    return 0;
}

函数重载的概述

//函数名可以相同,提高复用性
//函数重载满足条件如下:
//同一个作用域下,函数名称相同,函数参数类型不同或者个数不同或者顺序不同
#include<iostream>
using namespace std;
//同一作用域下,函数名称相同
void func() {
    cout << "func的调用" << endl;
}
void func(int a) {//参数类型或者个数不同
    cout << "func(int a)的调用" << endl;
}
void func(double a) {
    cout << "func(double a)的调用" << endl;
}
void func(double a,int b) {//参数类型顺序不同
    cout << "func(double a,int b)的调用" << endl;
}
void func(int b,double a) {
    cout << "func(int b,double a)的调用" << endl;
}
int main3() {
    func();
    func(10);
    func(3.14);
    func(3.14, 10);
    func(10, 3.14);
    //函数的返回值不可以作为函数承载的返回值条件
    return 0;
}

函数重载的注意事项

//引用作为重载条件;函数重载碰到函数默认参数
#include<iostream>
using namespace std;
void func(const int &a) {
    cout << "func(const int &a)的调用" << endl;
}

void func(int& a) {//int &a=10;这个语句不合法,所以func(10)走上面的函数
    cout << "func(int &a)的调用" << endl;
}
void func2(int a, int b=10) {
    cout << "func(int a,int b)的调用" << endl;
}
void func2(int a) {
    cout << "func(int a)的调用" << endl;
}
int main() {
    int a = 10;
    func(a);//调用可读可写的函数
    func(10);//调用const
    func2(a,20);
    return 0;
}

文件操作

写文件

//ofstream写操作-output
//ifstream读操作-input
//fstream读写操作
#include<iostream>
#include<fstream>
using namespace std;
void test01() {
    ofstream ofs;
    ofs.open("text.txt", ios::out);
    ofs << "姓名:张三" << endl;
    ofs << "性别:男" << endl;
    ofs << "年龄:18" << endl;
    ofs.close();
}
int main() {
    test01();
    return 0;
}

读文件

#include<iostream>
#include<fstream>
#include<string>
//EOF--->end of file
using namespace std;
void test01() {
    ifstream ifs;
    ifs.open("test.txt", ios::in);
    if (!ifs.is_open()) {
        cout << "error" << endl;
        return;
    }

    /*char buf[1024] = { 0 };
    while (ifs >> buf) {
        cout << buf << endl;
    }
    ifs.close();*/

    /*char buf[1024] = { 0 };
    while (ifs.getline(buf, sizeof(buf))) {
        cout << buf << endl;
    }
    ifs.close();*/

    string buf;
    while (getline(ifs, buf)) {//需要用循环来获取数值
        cout << buf << endl;
    }
    ifs.close();
}
int main() {
    test01();
    return 0;
}

二进制文件

#include<iostream>
#include<fstream>
//二进制文件使用write进行写文件操作
using namespace std;
struct Person {
    char m_Name[64];
    int m_Age;
};
void test01() {
    ofstream ofs("person.txt", ios::out | ios::binary);
    Person p = { "张三",18 };
    ofs.write((const char*)&p, sizeof(Person));//数据的地址以const char* 的方式传入,sizeof体现出要写多长
    ofs.close();
}
void test02() {
    ifstream ifs("person.txt", ios::in | ios::binary);
    if (!ifs.is_open()) {
        cout << "error" << endl;
        return;
    }
    else {
        Person p;
        ifs.read((char*)&p, sizeof(p));
        cout << "姓名:" << p.m_Name << endl;
        cout << "年龄:" << p.m_Age << endl;
        ifs.close();
    }
}
int main() {
    //test01();
    test02();
    return 0;
}

类和对象

友元

全局函数做友元

//有些私有属性也想让类外的函数或类来访问,关键字为friend
#include<iostream>
#include<string>
using namespace std;
class Building {
    //友元写到类里面就彳亍
    friend void goodGay(Building& building);//让goodGay是Building的好朋友,可以访问私有成员
public:
     Building() {
        m_SittingRoom = "客厅";
        m_BedRoom = "卧室";
    }
public:
    string m_SittingRoom;//客厅

private:
    string m_BedRoom;//卧室
};
//全局函数
void goodGay(Building &building) {
    cout << "好基友 正在访问:" << building.m_SittingRoom << endl;

    cout << "好基友 正在访问:" << building.m_BedRoom << endl;
}
int main() {
    Building building;
    goodGay(building);
    return 0;
}

友元类

#include<iostream>
using namespace std;
class Building02 {
    friend class goodGay02;//goodGay可以访问本类私有的成员
public:
    Building02();
public:
    string m_Sittingroom;
private:
    string m_Bedroom;
};
class goodGay02 {
public:
    goodGay02();

public:
    Building02* building;
    void visit();//参观函数,访问building中的属性


};
//类外写成员函数
Building02::Building02() {
    m_Sittingroom = "客厅";
    m_Bedroom = "卧室";
}
goodGay02::goodGay02() {
    //创建建筑物对象
    building = new Building02;
}
void goodGay02::visit() {
    cout << "好基友正在访问:" << building->m_Sittingroom << endl;

    cout << "好基友正在访问:" << building->m_Bedroom << endl;
}
void test01(){
    goodGay02 gg;
    gg.visit();
}
int main() {
    test01();
    return 0;
}

成员函数做友元

#include<iostream>
using namespace std;
class Building03;
class goodgay {
public:
    goodgay();
    void visit();//让visit可以访问building中的私有成员
    void visit02();
    Building03* building;
};
class Building03 {
    friend void goodgay::visit();//告诉编译器,这是一个goodgay下的visit函数作为友元
public:
    Building03();
public:
    string sittingroom;
private:
    string bedroom;
};
//类外实现成员函数
Building03::Building03() {
    sittingroom = "客厅";
    bedroom = "卧室";
}
goodgay::goodgay() {
    building = new Building03;
}
void goodgay::visit() {
    cout << "visit正在访问:" << building->sittingroom << endl;
    cout << "visit正在访问:" << building->bedroom << endl;
}
void goodgay::visit02() {
    cout << "visit02正在访问:" << building->sittingroom << endl;
    //cout << "visit02正在访问:" << building->bedroom << endl;  访问不了
}
void test01() {
    goodgay gg;
    gg.visit();
    gg.visit02();
}
int main() {
    test01();
    return 0;
}

对象特性

深拷贝和浅拷贝

#include<iostream>
using namespace std;
//浅拷贝:简单的赋值操作
//深拷贝:在堆区重新申请空间,进行拷贝操作
class Person05 {
public:
    Person05() {
        cout << "默认构造函数调用" << endl;
    }
    Person05(int age,int height) {
        m_Age = age;
        m_Height=new int(height);//new int返回的是int* 
        cout << "有参构造函数调用" << endl;
    }
    Person05(const Person05 &p) {
        m_Age = p.m_Age;
        m_Height = new int(*p.m_Height);//深拷贝
    }
    ~Person05() {
        //析构将在堆区的数据释放
        if (m_Height != NULL) {
            delete m_Height;
            m_Height = NULL;//防止出现野指针
        }
        cout << "析构函数调用" << endl;
    }
    int m_Age;
    int* m_Height;
};
void test01() {
    Person05 p1(18,160);
    cout << "p1的年龄为:" << p1.m_Age << endl;
    cout << "p1的身高为:" << *p1.m_Height << endl;
    Person05 p2(p1);//浅拷贝
    cout << "p2的年龄为:" << p2.m_Age << endl;
    cout << "p2的身高为:" << *p2.m_Height << endl;
}
int main() {
    test01();
    return 0;
}

初始化列表

//构造函数:属性1(值1),属性2(值2)......{ }
#include<iostream>
using namespace std;
class Person06 {
public:
    //传统初始化
    /*Person06(int a,int b,int c) {
        m_A = a;
        m_B = b;
        m_C = c;
    }*/

    //初始化列表初始化属性
    Person06(int a,int b,int c) :m_A(a), m_B(b), m_C(c){

    }
    int m_A;
    int m_B;
    int m_C;
};
void test01() {
    Person06 p(10,20,30);
    cout << p.m_A << ' ' << p.m_B << ' ' << p.m_C << endl;
}
int main() {
    test01();
    return 0;
}

静态成员变量

//静态成员变量:所有对象共享同一份数据,在编译阶段分配内存,类内声明,类外初始化
//静态成员函数:所有对象共享同一个函数,静态成员函数只能访问静态成员变量
#include<iostream>
using namespace std;
class Person08 {
public:

    //类内声明
    static int m_A;


    //静态成员变量也是有访问权限的
private:
    static int m_B;

};
int Person08::m_A=100;//类外初始化
int Person08::m_B = 200;

void test01() {
    Person08 p;
    cout << p.m_A << endl;

    Person08 p2;
    p2.m_A = 200;//编译阶段共享同一份数据
    cout << p.m_A << endl;
}

void test02() {
    //静态成员变量,不属于某个对象上,所有对象共享同一份数据
    //可以通过对象或者类名进行访问
    Person08 p;
    cout << p.m_A << endl;//对象访问

    cout << Person08::m_A << endl;//类名访问

    //cout << Person08::m_B << endl;
    //无法访问,因为静态也是有私有权限的
}
int main() {
    //test01();
    test02();
    return 0;
}

静态成员函数

//静态成员函数:所有对象共享同一个函数,静态成员函数只能访问静态成员变量
#include<iostream>
using namespace std;

class Person09 {
public:
    static void func() {
        //m_B = 200;  静态成员函数不可以访问非静态成员
        m_A = 100;//静态成员函数可以访问静态成员变量
        cout << "static void func调用" << endl;
    }

    static int m_A;
    int m_B;

private://类外无法访问私有的静态成员函数
    static void func02() {
        cout << "func02的调用" << endl;
    }
};
int Person09::m_A = 0;
void test01() {
    //通过对象访问
    Person09 p;
    p.func();


    //通过类名访问
    Person09::func();
}
int main() {
    test01();
    return 0;
}

空指针访问成员函数

#include<iostream>
using namespace std;
class Person12 {
public:
    void showClassName() {
        cout << "this is Person class" << endl;
    }
    void showPersonAge() {

        if (this == NULL) {
            return;
        }
        cout << "age=" << this->m_Age << endl;
    }
    int m_Age;
};
void test01() {
    Person12* p = NULL;

    p->showClassName();

    p->showPersonAge();
}
int main() {
    test01();
    return 0;
}

const 修饰成员函数

/成员函数后加const后我们称为常函数
//常函数内不可以修改成员属性
//加上mutable后,常函数中依旧可以修改
#include<iostream>
using namespace std;

class Person13 {
public:
    void showPerson() const{


        //m_A = 100;错误的,因为此时m_A不可以更改
        m_B = 100;//正确的,因为m_B前面有mutable


        //隐含在每一个成员函数的内部都有一个this指针
        //this指针是指针常量,指向不能改
        //加入const后,指针变成了const Person* const this;
    }

    void func() {
        m_A = 100;
    }

    int  m_A;

    int mutable m_B;

};

//常对象
void test01() {
    const Person13 p;//常对象,不允许修改值
    //p.m_A = 100;  错误的,因为修改不了
    p.m_B = 100;  //正确的,因为有mutable

    //常对象只能调用常函数
    p.showPerson();
    //p.func();  错误的,因为func不是常函数
}

继承

继承中的对象模型

在继承中,父类中所有的非私有成员属性都会被子类继承下去,而父类中私有的成员属性是被编译器给隐藏了,所以访问不到,但是确实被继承下去了。

继承中同名成员的处理方式

//访问子类同名成员,直接访问即可
//访问父类同名成员,需要加作用域
//如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有同名的成员函数(包括函数的重载)
#include<iostream>
using namespace std;

//继承中同名成员处理
class Base05 {
public:
    int m_A;
    Base05() {
        m_A = 100;
    }
    void func() {
        cout << "Base - func调用" << endl;
    }
    void func(int a) {
        cout << "Base - func(int a)调用" << endl;
    }
};
class Son05 :public Base05 {
public:
    Son05() {
        m_A = 200;
    }
    int m_A;
    void func() {
        cout << "Son - func调用" << endl;
    }
};
void test01() {
    Son05 s;//出现同名直接访问则访问自身
    cout << "m_A = " << s.m_A << endl;
    //访问base下的m_A需要加上作用域
    cout << "m_A = " << s.Base05::m_A << endl;
}
//同名函数处理
void test02() {
    Son05 s;
    s.func();//直接调用的调用的是子类中的成员
    s.Base05::func();//加上作用域就可以访问到父类的成员
    s.Base05::func(1);//同样也需要加上作用域
}
int main() {
    //test01();
    test02();
    return 0;
}

继承中同名静态成员的处理方式

//静态成员类内声明类外初始化,所有对象共享一份数据,编译阶段便分配内存
//静态成员函数只能访问静态成员变量
//可以通过对象访问,也可以通过类名访问
#include<iostream>
using namespace std;

//继承中的同名静态成员处理方式
class Base06 {
public:
    static int m_A;

    static void func() {
        cout << "Base-static void func()" << endl;
    }
};
int Base06::m_A = 100;
class Son06 :public Base06 {
public:
    static int m_A;

    static void func() {
        cout << "Son-static void func()" << endl;
    }
};
int Son06::m_A = 200;
void test01() {
    //静态同名成员属性
    //通过对象访问
    Son06 s;
    cout << "Son-m_A = " << s.m_A << endl;
    cout << "Base-m_A = " << s.Base06::m_A << endl;//同样要加作用域

    //通过类名访问
    cout << "类名访问" << endl;
    cout << "Son-m_A = " << Son06::m_A << endl;
    cout << "Base-m_A = " << Son06::Base06::m_A << endl;//第一个::代表通过类名方式访问,第二个::代表通过父类作用域下访问

}
void test02() {
    //同名静态成员函数
    Son06 s;
    s.func();
    s.Base06::func();//通过对象访问

    Son06::func();
    Base06::func();//通过类名访问
}

int main() {
    //test01();
    test02();
    return 0;
}

多态

多态基本语法

//多态分为静态多态(函数,运算符重载)和动态多态(派生类和虚函数)
//动态多态的函数地址在运行阶段再确定其地址
#include<iostream>
using namespace std;
//多态
//动物类
class Animal {
public:
    virtual void speak() {//虚函数,地址晚绑定
        cout << "动物在说话" << endl;
    }
};
//猫类
class Cat :public Animal {
public:
    void speak() {
        cout << "小猫在说话" << endl;
    }
};
//狗类
class Dog :public Animal {
public:
    void speak() {
        cout << "小狗在说话" << endl;
    }
};

//执行说话的函数
//地址早绑定:在编译阶段就确定函数地址
//如果想执行让猫说话,那么这个地址需要在运行阶段进行绑定,也就是地址晚绑定
void doSpeak(Animal &animal) {
    animal.speak();
}
void test01() {
    Cat cat;
    doSpeak(cat);
    //父类的引用指向子类对象,C++允许父类的引用可以和子类进行转换

    Dog dog;
    doSpeak(dog);

    cout << sizeof(Animal) << endl;
    //virtual 的时候会生成一个指针vfptr虚函数指针,子类通过继承覆盖指针的地址来重写函数
}
int main() {
    //动态多态满足条件:
    //1、有继承条件
    //2、子类重写父类的虚函数
    //重写:函数返回值类型 函数名 参数列表要完全相同

    //动态多态的使用
    //父类的指针或者引用来指向子类对象
    //Animal& animal = cat ;
    test01();

    return 0;
}

纯虚函数和抽象类

//多态中,父类的虚函数的实现是毫无意义的,主要都是调用子类重写的内容
//因此可以将虚函数改为纯虚函数
//抽象类的子类必须重写父类的纯虚函数,否则子类也是抽象类
//语法:virtual 返回值类型 函数名(参数列表)= 0 ;
//当类中有了纯虚函数,这个类也叫抽象类,无法实例化对象
#include<iostream>
using namespace std;
class Base {
public:
    virtual void func() = 0;//纯虚函数
    //这个类只要有一个纯虚函数,这个类叫做抽象类,无法实例化对象
};
class Son :public Base {
public:
    void func() {
        cout << "纯虚函数的重写" << endl;
    }
};
void test01() {
    Base* base = new Son;
    base->func();
}
int main() {
    test01();
    return 0;
}

虚析构和纯虚析构

//多态使用的时候,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
//解决方式:将父类中的析构函数改为虚析构或者纯虚析构
#include<iostream>
using namespace std;
class Animal05 {
public:
    Animal05() {
        cout << "Animal的构造函数" << endl;
    }
    /*virtual ~Animal05() {
        cout << "Animal的析构函数" << endl;
    }*/

    virtual ~Animal05() = 0;//纯虚析构

    //纯虚函数
    virtual void speak() = 0;
};
//纯虚析构,需要类内声明类外定义
//有了纯虚析构之后,这个类也属于抽象类,无法实例化对象
Animal05::~Animal05() {
    cout << "Animal的纯虚析构函数" << endl;
}

//父类的纯虚函数子类必须重写,否则子类也是抽象类
class Cat05 : public Animal05 {
public:
    Cat05(string name) {
        cout << "Cat的构造函数调用" << endl;
        m_Name = new string(name);
    }
    virtual void speak() {
        cout <<*m_Name<< "小猫在说话" << endl;
    }
    ~Cat05() {
        if (m_Name != NULL) {
            cout << "Cat的析构函数调用" << endl;
            delete m_Name;
            m_Name = NULL;
        }
    }
    string* m_Name;
};

void test01() {
    Animal05* animal = new Cat05("Tom");
    animal->speak();
    //父类指针在析构的时候,不会调用子类的析构函数,导致子类如果有堆区的数据,会出现内存泄漏
    //利用虚析构可以解决父类指针释放子类对象不干净的问题
    delete animal;
}
int main() {
    test01();
    return 0;
}

案例-电脑组装需求

//电脑组装需要CPU,显卡,内存条
//将每个零件封装出抽象基类,并且提供不同的厂商生产的不同的零件
//创建电脑类提供让电脑工作的函数,并且调用每个零件工作的接口
//测试时组装三台不同的电脑进行工作
#include<iostream>
using namespace std;

//先写出每个零件的抽象类,然后再让具体的厂商去继承零件的抽象类做具体实现

//抽象CPU类
class CPU {
public:
    virtual void calculate() = 0;
};

//抽象显卡类
class VideoCard {
public:
    virtual void display() = 0;
};

//抽象内存条类
class Memory {
public:
    virtual void storage() = 0;
};

//电脑类
class Computer {
public:
    Computer(CPU* cpu, VideoCard* vc, Memory* mem) {
        m_cpu = cpu;
        m_vc = vc;
        m_mem = mem;
    }

    //提供工作函数
    void Work() {
        //调用零件工作接口
        m_cpu->calculate();
        m_vc->display();
        m_mem->storage();
    }

    //析构函数释放堆区数据
    ~Computer() {
        if (m_cpu != NULL) {
            delete m_cpu;
            m_cpu = NULL;
        }
        if (m_vc != NULL) {
            delete m_vc;
            m_vc = NULL;
        }
        if (m_mem != NULL) {
            delete m_mem;
            m_mem = NULL;
        }
    }

private:
    CPU* m_cpu;//创建cpu零件指针
    VideoCard* m_vc;//显卡指针
    Memory* m_mem;//内存条指针
};

//具体厂商
//Intel 厂商
class IntelCpu :public CPU {
public:
    void calculate() {
        cout << "Intel的cpu开始计算" << endl;
    }
};
class IntelVideoCard :public VideoCard {
public:
    void display() {
        cout << "Intel的显卡开始显示" << endl;
    }
};
class IntelMemory :public Memory {
public:
    void storage() {
        cout << "Intel的内存条开始存储了" << endl;
    }
};

//Lenovo 厂商
class LenovoCpu :public CPU {
public:
    void calculate() {
        cout << "Lenovo的cpu开始计算" << endl;
    }
};
class LenovoVideoCard :public VideoCard {
public:
    void display() {
        cout << "Lenovo的显卡开始显示" << endl;
    }
};
class LenovoMemory :public Memory {
public:
    void storage() {
        cout << "Lenovo的内存条开始存储了" << endl;
    }
};

//开始测试组装
void test01() {
    //电脑零件
    CPU* intelCpu = new IntelCpu;
    VideoCard* intelCard = new IntelVideoCard;
    Memory* intelMem = new IntelMemory;

    //第一台电脑
    Computer* computer1 = new Computer(intelCpu, intelCard, intelMem);
    computer1->Work();
    delete computer1;
}
int main() {
    test01();
    return 0;
}

运算符重载

加号运算符重载

//对运算符进行重载,赋予其另一种功能
#include<iostream>
using namespace std;
class Person {
public:
    //成员函数重载+号
    //Person operator+(Person& p) {
    //    Person temp;
    //    temp.m_A = this->m_A + p.m_A;
    //    temp.m_B = this->m_B + p.m_B;
    //    return temp;
    //}
    int m_A;
    int m_B;
};

//全局函数重载+号
Person operator+(Person& p1, Person& p2) {
    Person temp;
    temp.m_A = p1.m_A + p2.m_A;
    temp.m_B = p1.m_B + p2.m_B;
    return temp;
}

//函数重载实现Person+int
Person operator+(Person& p1, int num) {
    Person temp;
    temp.m_A = p1.m_A + num;
    temp.m_B = p1.m_B + num;
    return temp;
}
void test01() {
    Person p1;
    p1.m_A = 10;
    p1.m_B = 10;

    Person p2;
    p2.m_A = 10;
    p2.m_B = 10;

    Person p3 = p1 + p2;
    cout << "p3.m_A" << ' ' << p3.m_A << endl;
    cout << "p3.m_B" << ' ' << p3.m_B << endl;

    //运算符重载也可以发生函数重载
}
int main() {
    test01();
    return 0;
}

递增运算符重载

#include<iostream>
using namespace std;
//重载递增运算符

//自定义整型
class myInt {
public:
    friend ostream& operator<<(ostream& cout, myInt myint);
    myInt() {
        m_Num = 0;
    }

    //重载++运算符(前置递增)
    myInt operator++() {//返回引用可以让我们一直对一个数据进行操作
        m_Num++;
        return *this;
    }

    //重载++运算符(后置递增)
    //这个int代表占位参数,用于区分前置和后置递增
    myInt operator++(int) {
        //先返回值,再做运算

        //先 记录当时结果
        myInt temp = *this;
        //后 递增
        m_Num++;
        //最后将记录的结果进行返回
        return temp;//返回的是局部对象的引用,如果直接返回引用,就会出问题
    }


private:
    int m_Num;
};
//重载左移运算符
ostream& operator<<(ostream& cout, myInt myint) {
    cout << myint.m_Num;
    return cout;
}

void test01() {
    myInt myint;
    //cout <<++myint << endl;//需要先重载左移运算符
    cout << myint.operator++() << endl;
}

void test02() {
    myInt myint;
    cout << myint++<< endl;
    cout << myint .operator++(4)<< endl;
}
int main() {
    //test01();
    test02();
    /*int a = 1;
    cout <<a++<< endl;
    cout << a << endl;*/
    return 0;
}

左移运算符重载

//重载左移运算符可以输出自定义的数据类型
#include<iostream>
using namespace std;

//左移运算符重载
class Person03 {
public:

    //不会利用成员函数重载左移运算符,因为无法实现cout在左侧
    //只能利用全局函数重载左移运算符
    int m_A;
    int m_B;
};


ostream& operator<<(ostream &cout,Person03 p) {//本质:operator<<(cout,p)  简化为cout<<p
    cout << p.m_A << ' ' << p.m_B ;
    return cout;//链式编程思想
}

void test01() {
    Person03 p;
    p.m_A = 10;
    p.m_B = 10;

    cout << p<<endl;
}
int main() {
    test01();
    return 0;
}

赋值运算符重载

#include<iostream>
using namespace std;
//赋值运算符重载
class Person04 {
public:

    Person04(int age) {
        m_Age=new int(age);
    }
    ~Person04() {
        if (m_Age != NULL) {
            delete m_Age;
            m_Age = NULL;
        }
    }

    //重载赋值运算符
    Person04& operator=(Person04 &p) {
        //编译器提供的是浅拷贝
        //应该先判断是否有属性在堆区,如果有,就要先释放干净,再深拷贝
        if (m_Age != NULL) {
            delete m_Age;
            m_Age = NULL;
        }
        m_Age= new int(*p.m_Age);
        return *this;
    }
    int* m_Age;
};

void test01() {
    Person04 p1(18);

    Person04 p2(20);

    Person04 p3(30);

    cout << "p1的年龄:" << *p1.m_Age << endl;

    cout << "p2的年龄:" << *p2.m_Age << endl;

    p3 = p2 = p1;//赋值操作
    cout << "p1的年龄:" << *p1.m_Age << endl;

    cout << "p2的年龄:" << *p2.m_Age << endl;

}
int main() {

    test01();

    /*int a = 10;
    int b = 20;
    int c = 30;
    c = b = a;
    cout << a << ' ' << b << ' ' << c << endl;*/
    return 0;
}

关系运算符重载

#include<iostream>
using namespace std;
class Person05 {
public:
    Person05(string name, int age) {
        m_Name = name;
        m_Age = age;
    }

    //重载==号
    bool operator==(Person05& p) {
        if (p.m_Age == this->m_Age && p.m_Name == this->m_Name) {
            return true;
        }
        else {
            return false;
        }
    }
    string m_Name;
    int m_Age;
};
void test01() {
    Person05 p1("Tom", 18);

    Person05 p2("Tom", 18);

    if (p1 == p2) {
        cout << "p1与p2相等" << endl;
    }
    else {
        cout << "p1与p2不相等" << endl;
    }
}
int main() {
    test01();
    return 0;
}

函数调用运算符重载

//函数调用运算符()也可以重载
//由于重载后的使用方式非常像函数的调用,因此称为仿函数
//仿函数没有固定写法,非常灵活
#include<iostream>
using namespace std;

//打印输出类
class MyPrint {
public:
    //重载函数调用运算符
    void operator()(string test) {
        cout << test << endl;
    }

};

void test01() {
    MyPrint myPrint;
    myPrint("hello world");//由于使用起来非常类似于函数调用,因此也叫做仿函数

}

//仿函数非常灵活,没有固定写法
//加法类
class MyAdd {
public:

    int operator()(int num1, int num2) {
        return num1 + num2;
    }
};

void test02() {
    MyAdd myadd;
    int ans=myadd(100, 100);
    cout << ans << endl;
}
int main() {
//    test01();
    test02();
    return 0;
}

函数对象

#include<iostream>
using namespace std;
//重载函数调用操作符(也就是小括号)的类,其对象称为函数对象
//函数对象使用重载的()时,行为类似函数调用,也叫仿函数
//函数对象是一个类,不是一个函数

class MyAdd {
public:
    int operator()(int v1, int v2) {
        return v1 + v2;
    }
};

void test01() {//函数对象使用的时候,可以像普通函数那样调用,可以有参数,也可以有返回值

    MyAdd myAdd;//函数对象
    cout << myAdd(10, 10) << endl;

}

//函数对象超出普通函数的概念,函数对象可以有自己的状态
class MyPrint {
public:
    MyPrint() {
        this->count = 0;
    }
    void operator()(string test) {
        cout << test << endl;
        this->count++;
    }
    int count;//内部的自己的状态,用来记录函数调用的次数
};

void test02() {
    MyPrint myPrint;
    myPrint("hello world!");
    cout << "函数调用次数:" << myPrint.count << endl;
}

void doPrint(MyPrint& mp,string& test) {
    mp(test);
}

//函数对象可以作为参数传递
void test03() {
    MyPrint myPrint;
    string test = "hello C++!";
    doPrint(myPrint, test);
}

int main() {

    //test01();
    //test02();
    test03();

    return 0;
}

内建函数对象

算数仿函数

#include<iostream>
#include<functional>
using namespace std;
//STL内建了一些函数对象——算数仿函数,关系仿函数,逻辑仿函数
//negate取反仿函数        plus加法仿函数

void test01() {

    negate<int> n;//模板

    cout<<n(50);

}

void test02() {

    plus<int> p;

    cout << p(10, 20);

}

int main() {
    //test01();
    test02();
    return 0;
}

关系仿函数

#include<iostream>
#include<functional>
#include<vector> 
#include<algorithm>
using namespace std;

//greater 大于 equal 等于 less 小于 not_equal_to 不等于

class MyCompare {
public:
    bool operator()(int val1, int val2) {
        return val1 > val2;
    }
};

void test01() {

    vector<int> v;
    v.push_back(10);
    v.push_back(50);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }
    //greater<int>() 是内建的函数对象,默认会使用less<>{}
    sort(v.begin(), v.end(), greater<int>());
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }

}

int main() {
    test01();
    return 0;
}

逻辑仿函数

#include<iostream>
#include<vector>
#include<functional>
#include<algorithm>
using namespace std;
//逻辑仿函数
//logical_and 与        logical_or 或            logical_not 非

void test01() {
    vector<bool> v;
    v.push_back(1);
    v.push_back(0);
    v.push_back(1);
    v.push_back(0);
    for (vector<bool>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }
    cout << endl;

    //利用逻辑非,将容器v搬运到容器v2中,并执行取反操作
    vector<bool> v2;
    v2.resize(v.size());
    transform(v.begin(), v.end(), v2.begin(), v2.end(), logical_not<bool>());
    for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++) {
        cout << *it << ' ';
    }
    cout << endl;
}

int main() {
    test01();
    return 0;
}

谓词

一元谓词

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
//返回bool类型的仿函数称为谓词( _Pred ) 
//如果接受一个参数,那么叫一元谓词
//如果接受两个参数,那么叫二元谓词

class GreaterFive {
public:
    bool operator()(int val) {
        if (val > 5) {
            return true;
        }
        else {
            return false;
        }
    }
};

void test01() {
    vector<int> v;
    for (int i = 1; i <= 10; i++) {
        v.push_back(i);
    }
    //查找容器中是否有大于5的数字
    vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());//匿名函数对象
    if (it == v.end()) {
        cout << "没有找到" << endl;
    }
    else {
        cout << "找到大于5的元素为:" << *it << endl;
    }
}


int main() {
    test01();
    return 0;
}

二元谓词

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

class MySort {
public:
    bool operator()(int val1, int val2) {
        return val1 > val2;
    }
};

static void test01() {

    vector<int> v;
    v.push_back(10);
    v.push_back(30);
    v.push_back(20);
    v.push_back(50);
    v.push_back(40);
    sort(v.begin(), v.end(), MySort());//匿名对象调用函数
    for (vector<int>::iterator it = v.begin(); it != v.end(); it++) {
        cout << *it << ' ';
    }

}


int main() {

    test01();

    return 0;
}

模板

函数模板

#include<iostream>
#include<algorithm>
using namespace std;

//两个整型交换
//void swapInt(int& a, int& b) {
//    int t = a;
//    a = b;
//    b = t;
//}

//交换两个浮点型
//void swapDouble(double& a, double& b) {
//    double t = a;
//    a = b;
//    b = t;
//}

template<typename T>//声明一个模板
void swapnum(T& a, T& b) {
    T t = a;
    a = b;
    b = t;
}
void test01() {

    int a = 10;
    int b = 20;
    swapnum(a, b);//自动类型推导
    cout << a << ' ' << b << endl;

    double c = 4.13;
    double d = 3.14;
    swapnum<double>(c, d);//显示指定类型
    cout << c << ' ' << d << endl;

}
int main() {
    test01();
    return 0;
}

函数模板的注意事项

#include<iostream>
using namespace std;
//函数模板的注意事项
//自动类型推导,必须推导出一致的数据类型T才可以使用
//模板必须要确定出T的数据类型,才可以使用
template<typename T>
void myswap(T& a, T& b) {
    T t = a;
    a = b;
    b = t;
}
template<typename C>
void func() {//错误的,因为template下面的函数模板必须要用到T
    cout << "hello world" << endl;
}
void test01() {
    int a = 10;
    int b = 20;
    myswap(a, b);
    cout << "a = " << a << ' ' << "b = " << b << endl;
    func<int>();//正确的,因为函数显示指定类型
}
int main() {
    test01();
    return 0;
}

普通函数与函数模板的区别

#include<iostream>
using namespace std;
//普通函数调用时可以发生自动类型转换(隐式类型转换)
//函数模板调用时,若利用自动类型推导,不会发生隐式类型转换
//如果利用显示指定类型的方式,可以发生隐式类型转换

//普通函数
int myAdd01(int a,int b) {
    return a + b;
}

//函数模板
template<typename T>
T myAdd02(T a, T b) {
    return a + b;
}

void test01() {
    int a = 10;
    double b = 3.14;
    cout << myAdd01(a, b) << endl;
}
void test02() {
    int a = 10;
    int b = 20;
    char c = 'a';
    cout << myAdd02(a, b) << endl;
    //cout << myAdd02(a, c) << endl;   错误的,因为函数模板没有办法进行隐式类型转换
    cout << myAdd02<int>(a, c) << endl;//正确的,因为显式指定类型可以进行隐式类型转换
}
int main() {
    //test01();
    test02();
    return 0;
}

普通函数与函数模板的调用规则

#include<iostream>
using namespace std;
//如果函数模板和普通函数都可以实现,优先调用普通函数
//可以通过空模板参数列表来强制调用函数模板
//函数模板也可以发生重载
//如果函数可以产生更好的匹配,优先调用函数模板
void myPrint(int a, int b) {
    cout << "调用普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b) {//函数重载
    cout << "调用模板函数" << endl;
}
template<typename T>
void myPrint(T a, T b,T c) {//重载函数模板
    cout << "调用重载的模板函数" << endl;
}
void test01() {
    int a = 10;
    int b = 20;
    myPrint(a, b);//优先调用普通函数

    //通过空模板参数列表,强制调用函数模板
    myPrint<>(a, b);
    myPrint(a, b, 100);

    //函数模板可以更好的匹配,优先调用函数模板
    char c1 = 'a';
    char c2 = 'b';
    myPrint(c1, c2);
}
//既然提供了函数模板,就不要提供了普通函数了,防止出现二义性
int main() {
    test01();
    return 0;
}

模板的局限性

#include<iostream>
using namespace std;

//模板的局限性
//模板并不是万能的,有些特定的数据类型需要具体化方式来实现

class Person {
public:
    Person(string name,int age) {
        this->m_Age = age;
        this->m_Name = name;
    }
    /*bool operator==(Person p) {
        if (this->m_Name == p.m_Name && this->m_Age == p.m_Age) {
            return true;
        }
        else {
            return false;
        }
    }*/
    string m_Name;
    int m_Age;
};
//对比两个数据是否相等的函数
template<typename T>
bool myCompare(T& a, T& b) {
    if (a == b) {
        return true;
    }
    return false;
}

//利用具体化的Person的版本来实现代码,具体化优先调用
template<>bool myCompare(Person& p1, Person& p2) {
    if (p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) {
        return true;
    }
    else {
        return false;
    }
}
void test01() {
    int a = 10;
    int b = 20;
    bool ret = myCompare(a, b);
    if (ret) {
        cout << "a==b" << endl;
    }
    else {
        cout << "a!=b" << endl;
    }
}
void test02() {
    Person p1("Tom", 10);
    Person p2("Tom", 10);
    bool ret = myCompare(p1, p2);
    if (ret) {
        cout << "p1==p2" << endl;
    }
    else {
        cout << "p1!=p2" << endl;
    }
}
int main() {
    //test01();
    test02();
    return 0;
}

类模板的语法

#include<iostream>
#include<vector>
using namespace std;

//类模板
template<class NameType,class AgeType>//两种不同类型的模板
class Person07 {
public:
    Person07(NameType name,AgeType age) {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson() {
        cout << "name:" << this->m_Name << endl;
        cout << "age:" << this->m_Age << endl;
    }
    NameType m_Name;
    AgeType m_Age;
};
void test01() {
    Person07<string, int>p1("sunwukong", 999);
    p1.showPerson();
}
int main() {
    test01();
    return 0;
}

类模板与函数模板的区别

#include<iostream>
using namespace std;
//类模板没有自动类型推导
//类模板在模板参数列表中可以有默认参数class T=int    该语法只能在类模板中使用

template<class NameType,class AgeType=int>//AgeType默认是整型
class Person08 {
public:
    Person08(NameType name, AgeType age) {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson() {
        cout << "age:" << this->m_Age << endl;
        cout << "name:" << this->m_Name << endl;
    }
    NameType m_Name;
    AgeType m_Age;
};
void test01() {
    //Person08 p("sunwukong", 999);  错误的,无法用自动类型推导
    Person08<string, int> p("sumwukong", 999);
    p.showPerson();
}
void test02() {
    Person08<string, int>p("zhubajie", 999);
}
int main() {
    test01();
    return 0;
}

类模板中的成员函数创建时机

//普通类中的成员函数一开始就可以创建
//类模板中的成员函数在调用的时候才创建
#include<iostream>
using namespace std;
//类模板中成员函数创建时机
class Person1 {
public:
    void showPerson1() {
        cout << "Person1 show" << endl;
    }
};
class Person2 {
public:
    void showPerson1() {
        cout << "Person2 show" << endl;
    }
};
template<class T>
class myClass {
public:
    T obj;//虚拟成员

    //类模板中的成员函数
    //没调用的时候不会创建
    void func1() {
        obj.showPerson1();
    }
    void func2() {
        obj.showPerson2();
    }
};
void test1() {
    myClass<Person1> m;
    m.func1();
    //m.func2();   
}
int main() {
    test1();
    return 0;
}

类模板对象做函数参数

//类模板实例化出对象,向函数传参的方式
//指定传入类型   参数模板化   整个类模板化
#include<iostream>
using namespace std;
template<class T1,class T2>
class Person {
public:
    Person(T1 name,T2 age) {
        this->m_Name = name;
        this->m_Age = age;
    }
    void showPerson() {
        cout << "name:" << m_Name << ' ' << "age:" << m_Age << endl;
    }
    T1 m_Name;
    T2 m_Age;
};
//指定传入类型(较常用)
void printPerson1(Person <string,int>&p) {
    p.showPerson();
}
void test01() {
    Person<string, int>p("sunwukong", 100);
    //p.showPerson();
    printPerson1(p);
}

//参数模板化
template<class T1,class T2>
void printPerson2(Person<T1,T2>&p) {
    p.showPerson();
    cout << "T1:" << typeid(T1).name() << endl;//typeid().name()可以显示出具体的数据类型
    cout << "T2:" << typeid(T2).name() << endl;
}
void test02() {
    Person<string, int>p("zhubajie", 90);
    printPerson2(p);
}

//整个类模板化
template<class T>
void printPerson3(T& p) {
    p.showPerson();
    cout << "T:" << typeid(T).name() << endl;
}
void test03() {
    Person<string, int> p("tangsen", 30);
    printPerson3(p);
}
int main() {
    //test01();
    //test02();
    test03();
    return 0;
}

类模板和继承

//子类继承的父类是一个类模板的时候,子类在声明时应该指明父类中T的类型
//如果想灵活指定父类中T的类型,子类也需要变为类模板
#include<iostream>
using namespace std;
template<class T>
class Base {
    T m;
};
//class Son :public Base {
//        错误的,因为子类继承的时候没有写明父类中T的参数类型
//};
class Son :public Base<int> {
    //正确的,这里指定了父类的参数类型是int
};
void test01() {
    Son s1;
}

//如果想灵活指定父类中T的类型,子类也要变成模板
template<class T1,class T2>
class Son2 :public Base<T1> {
public:
    Son2() {
        cout << "T1:" << typeid(T1).name() << endl;
        cout << "T2:" << typeid(T2).name() << endl;
    }
    T2 obj;
};
void test02() {
    Son2<int, char>s2;
    //int m;
    //char obj;
}
int main() {
    //test01();
    test02();
    return 0;
}

类模板成员函数的类外实现

#include<iostream> 
using namespace std;
//类模板成员函数类外实现
template<class T1,class T2>
class Person {
public:
    Person(T1 name, T2 age); 
    void showPerson(); 
    T1 m_Name;
    T2 m_Age;
};

//构造函数的类外实现
template<class T1,class T2>//先声明虚数据类型
Person<T1,T2>::Person(T1 name, T2 age) {//作用域和参数列表都要加虚数据类型
    this->m_Age = age;
    this->m_Name = name;
}

//成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson() {
    cout << "name:" << this->m_Name << "\n" << "age:" << this->m_Age << endl;
}
void test01() {
    Person<string, int> p("Tom", 30);
    p.showPerson();
}
int main() {
    test01();
    return 0;
}

类模板与友元

#include<iostream>
using namespace std;
//通过全局函数来打印Person信息

//--------------------------------------------------------------------------------------------//
//全局函数类外实现要先让编译器看到这个类外的代码
template<class T1,class T2>
class Person14;
template<class T1, class T2>
void printPerson2(Person14<T1, T2> p) {
    cout << "类外name:" << p.m_Name << endl << "类外age:" << p.m_Age << endl;
}
//--------------------------------------------------------------------------------------------//
                                                                                                                                // ^
template<class T1,class T2>                                                                                     // |
class Person14 {                                                                                                         // |
public:                                                                                                                         // |
    //全局函数类内实现                                                                                                 // |
    friend void printPerson(Person14<T1, T2> p) {                                                     // |
        cout << "name:" << p.m_Name << endl << "age:" << p.m_Age << endl;   // |
    }                                                                                                                             // |
                                                                                                                                 // |
    //全局函数类外实现                                                                                               // |
    //加空模板的参数列表,不然类内是普通函数声明,类外是模板函数定义                     |
    friend void printPerson2<>(Person14<T1, T2> p);//--------------------------------

    Person14(T1 name,T2 age) {
        this->m_Name = name;
        this->m_Age = age;
    }
private:
    T1 m_Name;
    T2 m_Age;
};

void test01() {
    Person14<string, int>p("Tom", 20);
    //printPerson(p);
    printPerson2(p);
}
int main() {
    test01();
    return 0;
}
//建议全局函数做类内实现,用法简单,并且编译器可以直接识别

类模板的分文件编写

person.hpp 文件如下:

#pragma once
#include<iostream>
using namespace std;

template<class T1, class T2>
class Person13 {
public:
    Person13(T1 name, T2 age);
    void showPerson();
    T1 m_Name;
    T2 m_Age;
};
template<class T1, class T2>
Person13<T1, T2>::Person13(T1 name, T2 age) {
    this->m_Age = age;
    this->m_Name = name;
}
template<class T1, class T2>
void Person13<T1, T2>::showPerson() {
    cout << "age:" << this->m_Age << "\n" << "name:" << this->m_Name << endl;
}

main.cpp 文件如下:

//类模板中成员函数创建时机是在调用阶段,导致分文件编写的时候连接不到
//解决:直接包含cpp或者声明和实现写同一个文件里,  后缀名改为.hpp文件
#include<iostream>
using namespace std;
#include"person.hpp"
//template<class T1,class T2>
//class Person {
//public:
//    Person(T1 name, T2 age);
//    void showPerson();
//    T1 m_Name;
//    T2 m_Age;
//};
//template<class T1,class T2>
//Person<T1, T2>::Person(T1 name, T2 age) {
//    this->m_Age = age;
//    this->m_Name = name;
//}
//template<class T1, class T2>
//void Person<T1, T2>::showPerson() {
//    cout << "age:" << this->m_Age << "\n" << "name:" << this->m_Name << endl;
//}
void test01() {
    Person13<string, int> p("Jerry", 18);
    p.showPerson();
}
int main() {
    test01();
    return 0;
}

文章作者: 热心市民灰灰
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 热心市民灰灰 !
  目录