c++ 学习笔记

1 返回局部变量地址

  1. 不要返回局部变量的地址 local variables,这里的地址存储在栈区,函数运行结束后编译器自动释放
  2. 编译器可能会保留一次数据,所以第一次输出可能是对的

#include <iostream>
using namespace std;

int *func(){
    int *a=10;
    cout<<&a<<endl;
    return a;
}
int main() {
    int a=10;

    int *p = NULL;
    p = func();

    cout<<*p<<endl;
    cout<<"address:"<<endl;
    cout<<p<<endl;
    cout<<p<<endl;
    cout<<*p<<endl;
    cout<<*p<<endl;
    return 0;
}

/*
0x61fdd8
-1163005939
address:
0x764040
0x764040
-1163005939
-1163005939
*/

形参也是一样的

  1. 放在堆区的可以返回,由程序员决定什么时候释放
#include <iostream>
using namespace std;

int *func(){
    int *a=NULL;
    a=new int(10);
    cout<<&a<<endl;
    cout<<&a<<endl;
    return a;
}
int main() {
    int a=10;

    int *p = NULL;
    p = func();

    cout<<*p<<endl;
    cout<<"address:"<<endl;
    cout<<p<<endl;
    cout<<p<<endl;
    cout<<*p<<endl;
    cout<<*p<<endl;
    delete p;

    cout<<*p<<endl;

    return 0;
}

/*
0x61fdd8
0x61fdd8
10
address:
0x774040
0x774040
10
10
6495408
*/

2 引用&

  1. datatype &newname = originname
  2. 可以从中间引用数组
#include <iostream>
using namespace std;

void func(int arr[],int n){
    for(int i=0;i<n;i++){
        cout<<arr[i]<<endl;
    }
}

int main() {
    int arr[]={1,2,3,4,5,6,7,8};
    int n=8;
    func(&arr[n/3],n-n/3);
    return 0;
}

/*
3
4
5
6
7
8
*/
  1. 必须初始化,且初始化以后不能更改引用为其他
#include <iostream>
using namespace std;

int main() {
    int a = 10;
    int c = 20;

    //必须初始化
    // int &b;

    //初始化以后不能更改
    int& b = a;
    b = c;  //这只是赋值,并不是更改引用
    cout << b << endl;

    return 0;
}
  1. 引用作为函数返回值
    返回局部变量
    下面这个程序在vscode中直接报错,在vs中可以运行
#include <iostream>
using namespace std;

int& func() {
    int a = 10;
    return a;
}

int main() {
    int& ref = func();
    cout << ref << endl;//第一次编译器做了保留
    cout << ref << endl;//第二次错误,a的内存已经被释放

    return 0;
}

/*
reference to local variable 'a' returned [-Wreturn-local-addr]
*/
  1. 函数调用作为左值
#include <iostream>
using namespace std;

int& func() {
    static int a = 10;  //静态变量,放在全局区,程序结束后才会被释放
    return a;
}

int main() {
    int& ref = func();
    cout << ref << endl;
    cout << ref << endl;

    func() = 1000;  //函数的调用可以作为左值
    cout << ref << endl;
    cout << ref << endl;

    return 0;
}

/*
10
10
1000
1000
*/
  1. 引用&的本质是指针
#include <iostream>
using namespace std;

//内部发现是引用,自动转换成为 int*const ref = &a;
void func(int& ref) {
    ref = 100;  //自动转换为 *ref=100;
}

int main() {
    int a = 10;

    //自动转换为 int* const ref = &a;指针常量是指针不可修改,也对应引用不可修改
    int& ref = a;
    ref = 20;  //内部发现ref是引用,自动帮我们进行转换为: *ref = 20;

    cout << "a: " << a << endl;
    cout << "ref: " << ref << endl;

    func(a);
    cout << "ref: " << ref << endl;

    return 0;
}

/*
a: 20
ref: 20
ref: 100
*/
  1. 常量引用
#include <iostream>
using namespace std;

int main() {
    //常量引用

    //下面这行语句会报错
    // initial value of reference to non-const must be an lvalue
    // int &ref  =10;//引用必须是一块合法的空间

    //下面这个表达没有报错是因为编译器自动进行了一个操作,可以认为:
    // int tmp=10;const int &ref = tmp;
    const int& ref = 10;

    cout << ref << endl;

    return 0;
}

3 函数 function

  1. 函数形参默认值,如果某个形参有默认参数,后面的也必须有默认参数

错误写法

void func(int a, int b = 10, int c)

正确写法

#include <iostream>
using namespace std;

int func(int a, int b = 10, int c = 30) {
    return a + b + c;
}

int main() {
    int res;

    res = func(5);  //可以只传入没有默认参数的

    res = func(5, 30);  //编译对b的值使用用户传入的30

    return 0;
}
  1. 函数声明有默认参数,函数实现就不能再有,不然后有歧义,报错
//会报错
//函数声明和函数实现中形参的默认参数只能有一个有
int func(int a, int b = 10, int c = 30);

int func(int a, int b = 10, int c = 30) {
    return a + b + c;
}

/*
default argument given for parameter 2 of 'int func(int, int, int)' [-fpermissive]
*/
  1. 占位参数
#include <iostream>
using namespace std;

//第二个是占位参数
void func(int a, int) {
    cout << "Hello world!" << endl;
}

int main() {
    func(10, 10);  //第二个占位参数也要传入初始值
    return 0;
}

也可以有默认参数

#include <iostream>
using namespace std;

//第二个是占位参数,也可以有默认参数
void func(int a, int = 10) {
    cout << "Hello world!" << endl;
}

int main() {
    func(10);  //第二个占位参数可以不用传入初始值
    return 0;
}

4 函数重载

  1. 函数名可以相同,提高复用率
  2. 函数名称相同
  3. 参数类型不同,或者个数不同,或者顺序不同
  4. 返回类型不可以作为重载条件
#include <iostream>
using namespace std;

void func() {
    cout << "func1" << endl;
}

void func(int a) {
    cout << "func2" << endl;
}

void func(int a, double b) {
    cout << "func3" << endl;
}

void func(double a, int b) {
    cout << "func4" << endl;
}

//返回类型不可以作为重载的条件
/*
int func(double a,int b){
    cout<<"func5"<<endl;
}
*/

int main() {
    func();
    func(10);
    func(10, 3.14);
    func(3.14, 10);

    return 0;
}

/*
func1
func2
func3
func4
*/

注意事项

  1. 遇到引用
#include <iostream>
using namespace std;

void func(int& a) {  // int &a=10不合法,所以不会运行这个
    cout << "func1" << endl;
}

void func(const int& a) {
    cout << "func2" << endl;
}

int main() {
    int a = 10;
    func(a);
    func(10);

    return 0;
}

/*
func1
func2
*/
  1. 遇到默认参数
#include <iostream>
using namespace std;

void func(int a, int b = 10) {  // int &a=10不合法,所以不会运行这个
    cout << "func1" << endl;
}

void func(int a) {
    cout << "func2" << endl;
}

int main() {
    func(10);  //有二义性,会报错

    return 0;
}

所以要尽量避免产生歧义

5 类和对象

1) 类

  1. class和struct的唯一区别是默认权限不一样,前者是private,后者是public

2) 构造函数和析构函数

#include <iostream>
#include <string.h>

using namespace std;

//对象的初始化和清理
class Person {
  private:
    /* data */
  public:
    Person(/* args */);
    ~Person();
};

/*构造函数
没有返回值,不用写void
函数名与类名相同
可以有参数,可以重载
创建对象的时候,构造函数会自动调用,而且只调用一次*/
Person::Person(/* args */) {
    cout << "Person 构造函数的调用" << endl;
}

/*析构函数
没有返回值 不用写void
函数名与类名相同,前面加~
没有参数,不能重载
对象销毁前会自动调用,无需手动调用,而且只会调用一次
*/
Person::~Person() {
    cout << "Person 析构函数的调用" << endl;
}

int main() {
    Person p1;

    return 0;
}

/*
Person 构造函数的调用
Person 析构函数的调用
*/

构造函数

调用方式
#include <iostream>
#include <string.h>

using namespace std;

/*构造函数分类
按照参数分类 有参和无参构造,无参构造又称为默认构造
按照类型 普通构造和拷贝构造
*/

class Person {
  private:
    int age;

  public:
    Person(/* args */);
    Person(int);
    Person(const Person&);
    ~Person();
};

/*无参构造*/
Person::Person(/* args */) {
    cout << "默认构造函数的调用" << endl;
}

/*有参函数构造*/
Person::Person(int a) {
    age = a;
    cout << "有参函数的调用" << endl;
}

/*拷贝函数构造
使用const防止修改传入的数据,使用引用传入*/
Person::Person(const Person& p) {
    age = p.age;
    cout << "拷贝函数的调用" << endl;
}

/*默认析构函数
 */
Person::~Person() {
    cout << "默认析构函数的调用" << endl;
}

int main() {
    //调用构造函数

    // 1 括号法,常用
    //有参函数的调用
    Person p1(10);

    //使用默认构造不能加括号,不然ide认为这是一个函数声明
    //报错:'Person p1()' redeclared as different kind of symbol
    // Person p1();

    // 2 显示法
    //这是在声明一个匿名对象,马上就会被系统清理
    // Person(10);
    // Person p2(10);

    //有参函数的调用
    Person p2 = Person(10);
    // 拷贝函数的调用
    Person p3 = Person(p2);

    // 3 . 隐式转换法
    Person p4 = 10;  // Person p4 = Person(10);//有参函数的调用
    Person p5 = p4;  // Person p5=Person(p4);//拷贝函数的调用

    // notice
    //  不能利用拷贝构造函数初始化匿名对象,编译器会认为是对象声明
    //  Person p6(p5);

    return 0;
}
调用时机
#include <iostream>
#include <string.h>

using namespace std;

/*构造函数分类
按照参数分类 有参和无参构造,无参构造又称为默认构造
按照类型 普通构造和拷贝构造
*/

class Person {
  private:
    int age;

  public:
    Person(/* args */);
    Person(int);
    Person(const Person&);
    ~Person();
};

/*无参构造*/
Person::Person(/* args */) {
    cout << "默认构造函数的调用" << endl;
}

/*有参函数构造*/
Person::Person(int a) {
    age = a;
    cout << "有参函数的调用" << endl;
}

/*拷贝函数构造
使用const防止修改传入的数据,使用引用传入*/
Person::Person(const Person& p) {
    age = p.age;
    cout << "拷贝函数的调用" << endl;
}

/*默认析构函数
 */
Person::~Person() {
    cout << "默认析构函数的调用" << endl;
}

void func1(Person p) {
    cout << &p << endl;
    cout << "func1 函数被调用" << endl;
}

Person func2() {
    cout << "func2 函数被调用" << endl;
    Person p1;
    cout << &p1 << endl;
    return p1;
}

int main() {
    //调用构造函数的时机

    Person p1(10);
    cout << &p1 << endl;
    func1(p1);
    cout << &p1 << endl;

    Person p2 = func2();
    cout << &p2 << endl;
    return 0;
}
调用条件

声明一个对象时,系统会自动提供至少三个函数,默认构造函数,默认拷贝函数,默认析构函数
如果声明了有参函数,那么不再提供默认构造函数,如果声明了拷贝函数,那么不再提供默认构造和默认拷贝函数

深拷贝和浅拷贝
#include <iostream>
#include <string.h>

using namespace std;

/*构造函数
深拷贝与浅拷贝
使用编译器默认的拷贝函数会进行浅拷贝
浅拷贝其实就是使用同一个内存空间
*/

class Person {
  private:
    int age;
    int* hight = NULL;

  public:
    Person(/* args */);
    Person(int, int);
    Person(const Person&);
    void ShowInfo();
    ~Person();
};

/*无参构造*/
Person::Person(/* args */) {
    cout << "默认构造函数的调用" << endl;
}

/*有参函数构造*/
Person::Person(int a, int h) {
    age = a;
    hight = new int(h);  //声明对象在堆区,由程序员手动释放
    cout << hight << endl;
    cout << "有参函数的调用" << endl;
}

/*拷贝函数构造
使用const防止修改传入的数据,使用引用传入*/
Person::Person(const Person& p) {
    age = p.age;

    //编译器默认的这是这样拷贝的
    // hight = p.hight;
    // cout<<hight<<endl;

    // 我们自己进行深拷贝操作
    hight = new int(*p.hight);  //开辟另一个空间
    *hight = *p.hight;
    cout << hight << endl;

    cout << "拷贝函数的调用" << endl;
}

void Person::ShowInfo() {
    cout << "年龄是: " << age << endl;
    cout << "身高是: " << *hight << endl;
}

/*默认析构函数
 */
Person::~Person() {
    //将堆区开辟的空间进行释放
    // p2 先进行释放,然后p1再来一次释放,造成重复释放报错
    //浅拷贝造成的问题:内存重复释放
    if(hight) {
        delete hight;
        hight = NULL;  //防止野指针,进行置空
    }

    cout << "默认析构函数的调用" << endl;
}

int main() {
    Person p1(18, 170);

    p1.ShowInfo();

    Person p2(p1);
    p2.ShowInfo();

    return 0;
}
列表初始化
#include <iostream>
#include <string.h>

using namespace std;

class Person {
  private:
    int a;
    int b;
    int c;

  public:
    Person(int a1, int b1, int c1);
    void ShowSum();
    ~Person();
};

//列表初始化
Person::Person(int a1, int b1, int c1)
    : a(a1), b(b1), c(c1) {
}

void Person::ShowSum() {
    cout << a + b + c << endl;
}
Person::~Person() {
}

int main() {
    Person p1(10, 20, 30);
    p1.ShowSum();
    return 0;
}

/*
60
*/
类作为类成员

注意回收次序

#include <iostream>
#include <string.h>

using namespace std;

class Phone {
  public:
    Phone(string name) {
        PhoneName = name;
        cout << "Phone 构造函数" << endl;
    }
    ~Phone() {
        cout << "Phone 析构函数" << endl;
    }

    void showname() {
        cout << PhoneName;
    }

  private:
    string PhoneName;
};

class Person {
  public:
    Person(string name, string Phname)
        : Name(name), Mphone(Phname) {
        cout << "person 构造函数" << endl;
    }
    ~Person() {
        cout << "Person 析构函数" << endl;
    }

    void show() {
        cout << Name << " use ";
        Mphone.showname();
        cout << " telephone!" << endl;
    }

  private:
    string Name;
    Phone Mphone;
};

int main() {
    string name = "张三";
    string Phname = "HONOR";
    Person p1(name, Phname);
    p1.show();

    return 0;
}

/*
Phone 构造函数
person 构造函数
张三 use HONOR telephone!
Person 析构函数
Phone 析构函数
*/
静态成员变量
#include <iostream>
#include <string.h>

using namespace std;

/*静态成员变量特点
1. 在编译阶段分配内存
2. 类内声明,类外初始化
3. 所有对象共享同一份数据*/
class Person {
  private:
    //静态成员变量依然有访问权限
    static int age;

  public:
    void showage() {
        cout << age << endl;
    }
};

//类内声明,在类外初始化
int Person::age = 100;

int main() {
    Person p1;
    p1.showage();

    return 0;
}
静态成员函数
#include <iostream>
#include <string.h>

using namespace std;

/*静态成员函数特点
1. 所有对象共享同一个函数
2. 静态成员函数只能访问静态成员变量*/
class Person {
  private:
    //静态成员变量依然有访问权限
    static int age;
    int hight;

  public:
    static void showage() {
        // 无法访问非静态成员变量,
        // 非静态成员变量属于不同的对象,IDE无法分辨程序是想访问哪一个对象的变量
        // cout<<hight<<endl;
        cout << age << endl;
        cout << "静态成员函数的调用" << endl;
    }
};

//类内声明,在类外初始化
int Person::age = 100;

int main() {
    Person p1;
    //访问方式
    // 1. 通过对象来访问
    p1.showage();

    // 2. 通过类名访问
    // 所有对象共享同一个变量的地址
    Person::showage();

    return 0;
}

成员函数和成员变量分开存储

#include <iostream>
#include <string.h>

using namespace std;

/*成员变量和成员函数是分开存储的*/

class None {
};

class Person1 {
  private:
    //静态成员变量依然有访问权限
    static int age;
    //非静态成员变量
    int hight;
};
//类内声明,在类外初始化
int Person1::age = 100;

class Person2 {
  private:
    int hight;
};

class Person3 {
  private:
    int hight;

  public:
    void showhight() {
        cout << hight << endl;
    }
};

int main() {
    None n;
    //输出空对象所占用的内存大小
    // c++编译器会个每一个空对象分配1个字节的空间,为了区分空对象占用内存的位置
    // 每一个空对象都有一个独一无二的位置
    cout << "size of n " << sizeof(n) << endl;

    Person1 p1;
    //验证静态和非静态是分开存储的
    /*
    size of p1 4
    size of p2 4
    */
    cout << "size of p1 " << sizeof(p1) << endl;
    Person2 p2;
    cout << "size of p2 " << sizeof(p2) << endl;

    // size of p3 4
    // 成员函数也不是存数在类里面
    Person3 p3;
    cout << "size of p3 " << sizeof(p3) << endl;

    return 0;
}

this指针

#include <iostream>
#include <string.h>

using namespace std;

/*this指针
1. 解决名称冲突
2. 返回对象本身*/

class Person {
  public:
    //假如我们这样写就会发生名称重复
    // Person(int Age){
    //     Age = Age;
    // }

    //使用this来解决
    Person(int Age) {
        // this指针指向被调用的成员函数的所属的对象
        this->Age = Age;
    }
    void showAge() {
        cout << Age << endl;
    }

    //返回的对象就是他调用的对象本身
    // 下面两种返回类型得到的结果是不一样的
    // 1 不使用引用,这样返回的已经不是对象本身了,而是对象的一个副本
    // Person AddAge(const Person &p){
    //     this->Age+=p.Age;
    //     return *this;
    // }
    // 2. 使用引用
    Person& AddAge(const Person& p) {
        this->Age += p.Age;
        cout << Age << endl;
        return *this;
    }

  private:
    int Age;
};

int main() {
    Person p1(18);
    Person p2(18);

    p1.showAge();
    p2.showAge();

    p2.AddAge(p1);
    p2.showAge();

    //链式编程思想
    p2.AddAge(p1).AddAge(p1).AddAge(p1);
    p2.showAge();

    return 0;
}

/*
18
18
36
36
54
72
90
90
*/
空指针访问成员函数
#include <iostream>
#include <string.h>

using namespace std;

/*我们允许使用空指针访问成员函数*/

class Person {
  public:
    void showclasname() {
        cout << "this is Person class" << endl;
    }
    void showage() {
        //其实默认都加了一个this指针,即应该是this->Age这样,
        //使用空指针时,this->Age就会报错,上面的函数就没事

        // 一般解决办法,使用this之前先进行判断
        if(!this)
            return;
        cout << "age = " << Age << endl;
    }
    Person() {
        Age = 18;
    }

  private:
    int Age;
};

int main() {
    //声明一个空指针
    Person* p = NULL;
    p->showclasname();
    p->showage();

    return 0;
}

cosnt修饰成员函数

#include <iostream>
#include <string.h>

using namespace std;

/*常函数 常对象*/

class Person {
  public:
    void showclasname() {
        cout << "this is Person class" << endl;
    }
    void showage() const {
        //在成员函数后面写const修饰的是 this指针,让指针指向的值也不可以被修改
        // 报错语句
        // Age = 30;
        cout << "age = " << Age << endl;

        cout << "Hight  = " << Hight << endl;
        //常函数中也可以修改的值
        Hight = 175;
        cout << "Hight = " << Hight << endl;
    }
    Person() {
        Age = 18;
        Hight = 170;
    }
    //测试常对象不能修改变量值
    void chagevalue(int num) {
        Age = num;
    }

  private:
    int Age;
    //特殊变量,在常函数中也可以修改他的值
    mutable int Hight;
};

int main() {
    //声明一个空指针
    Person p;
    p.showclasname();
    p.showage();

    //在对象前面加上const 变成常对象
    Person p1;
    //常对象只能调用常函数,

    p1.showage();
    // 不可以调用普通成员函数,// 因为普通成员函数可以修改成员属性
    p1.chagevalue(25);
    p1.showage();
    return 0;
}

3) 友元函数

全局函数作为友元

#include <iostream>
#include <string.h>
using namespace std;

/*友元函数*/

class House {
    //写在最上面,告诉IDE这是一个全局函数
    friend void confidant(House&);

  private:
    string BedRoom;

  public:
    string SittingRoom;

    House() {
        BedRoom = "卧室";
        SittingRoom = "客厅";
    }
};

void confidant(House& h) {
    cout << "闺蜜正在访问" << h.SittingRoom << endl;
    cout << "闺蜜正在访问" << h.BedRoom << endl;
}

int main() {
    House h;
    confidant(h);
    return 0;
}

友元类

#include <iostream>
#include <string.h>
using namespace std;

/*友元类
可以访问私有*/

class House {
    //类作为友元
    friend class Confidant;

  private:
    string BedRoom;

  public:
    string SittingRoom;

    House() {
        BedRoom = "卧室";
        SittingRoom = "客厅";
    }
};

class Confidant {
  public:
    void visit(House& h) {
        cout << "闺蜜正在访问 " << h.SittingRoom << endl;
        cout << "闺蜜正在访问 " << h.BedRoom << endl;
    }
};
int main() {
    Confidant c;
    House h;

    c.visit(h);
    return 0;
}

成员函数作为友元函数

bug
#include <iostream>
#include <string.h>
using namespace std;

/*友元成员函数
可以访问私有*/

//先声明一下
class Confidant;

class House {
    //类成员函数作为友元
    // friend void Confidant::visit(House& h);
    friend void Confidant::visit(House& h);

  private:
    string BedRoom;

  public:
    string SittingRoom;

    House() {
        BedRoom = "卧室";
        SittingRoom = "客厅";
    }
};

class Confidant {
  public:
    void visit(House& h) {
        cout << "闺蜜正在访问 " << h.SittingRoom << endl;
        cout << "闺蜜正在访问 " << h.BedRoom << endl;
    }
};

int main() {
    Confidant c;
    House h;

    c.visit(h);
    return 0;
}

4) 运算符重载

+

bug
#include <iostream>
#include <string.h>
using namespace std;

/*运算符重载
 */
class Person {
  public:
    int a;
    int b;
    // int operator+(const Person& p) {
    //     return a + p.a;
    // }

    //运算符重载的函数重载
    // 这里不知道为什么老师的可以我的不可以,是ide的原因吗
    int operator+(int num1, int num) {
        return a + num1 + num;
    }

    int operator+(int num) {
        return a + num;
    }
};

int main() {
    Person p1;
    p1.a = 10;
    p1.b = 20;

    Person p2;
    p2.a = 30;
    p2.b = 40;

    //这两个表达是一样的,前者是简化的版本
    // cout << p1 + p2 << endl;
    // cout << p1.operator+(p2) << endl;

    cout << p1.operator+(10) << endl;
    cout << p1 + 10 << endl;
    // cout<<p1.operator+(p2,10);

    cout << p1 + 10 + 10 << endl;
    return 0;
}

<<

#include <iostream>
#include <string.h>
using namespace std;

class Person {
    friend ostream& operator<<(ostream&, Person&);

  public:
    void setvalue(int num1, int num2) {
        a = num1;
        b = num2;
    }

  private:
    int a;
    int b;
    //通常不用成员函数重载<<运算符,使用全局函数,
    //不然cout不会在左边
};

//注意返回值如果是void的话我们使用endl就会报错
//注意要用引用作为返回值,不然返回的是副本
ostream& operator<<(ostream& out, Person& p) {
    out << p.a << "  and  " << p.b;
    return out;
};

int main() {
    Person p;
    p.setvalue(100, 120);

    cout << p << endl;
    return 0;
}

/*
100  and  120
*/

++

#include <iostream>
#include <string.h>
using namespace std;

class Integer {
    friend ostream& operator<<(ostream&, Integer&);

  private:
    int Num;

  public:
    Integer() {
        Num = 10;
    }

    // 前置++重载
    Integer& operator++() {
        ++Num;
        return *this;
    }

    // 后置++重载
    // int代表的是一个占位参数,可以用于区分前置和后置
    Integer& operator++(int) {
        //记录这个值
        Integer* tmp = NULL;
        tmp = new Integer;
        *tmp = *this;
        // 进行递增
        Num++;
        // 返回记录的值
        return *tmp;
    }
};

ostream& operator<<(ostream& out, Integer& i) {
    out << i.Num;
    return out;
}

int main() {
    Integer i;
    cout << i << endl;

    cout << ++i << endl;

    cout << i++ << endl;

    cout << i << endl;
    return 0;
}

/*
10
11
11
12
*/

=

#include <iostream>
#include <string.h>
using namespace std;

/*
系统会自动给出一个赋值函数,但是涉及到深浅拷贝的问题
使用系统默认的这个函数回到导致后期重复释放的问题*/
class Person {
    friend ostream& operator<<(ostream& out, Person& i);

  private:
    //声明在堆区, 所以就涉及手动释放的问题
    int* Age = NULL;

  public:
    Person(int age) {
        Age = new int(age);
    }
    //使用系统默认的这个函数回到导致后期重复释放的问题
    Person& operator=(Person& p) {
        //编译器提供的是浅拷贝
        // Age = p.age;

        //先判断属性是否是在堆区,在的话清楚干净,然后再深拷贝
        if(Age) {
            delete Age;
            Age = NULL;
        }

        //深拷贝
        Age = new int(*p.Age);

        return *this;
    }
    ~Person() {
        if(Age) {  //如果不为空,我们就回收它
            delete Age;
            Age = NULL;
        }
    }
};

ostream& operator<<(ostream& out, Person& i) {
    out << *i.Age;
    return out;
}

int main() {
    Person p1(18);
    Person p2(20);
    Person p3(30);

    cout << p1 << endl;
    cout << p2 << endl;
    cout << p3 << endl;

    p3 = p2 = p1;

    cout << p1 << endl;
    cout << p2 << endl;
    cout << p3 << endl;

    return 0;
}

/*
18
20
30
18
18
18
*/

==

#include <cstdbool>
#include <iostream>
#include <string.h>
using namespace std;

/*
关系运算符*/
class Person {
  private:
    int Age;
    string Name;

  public:
    Person(int age, string name) {
        Age = age;
        Name = name;
    }

    bool operator==(const Person& p) const {
        if(Age == p.Age)
            return true;
        return false;
    }
};

bool func(const Person& p1, const Person& p2) {
    if(p1 == p2)
        return true;
    return false;
}

int main() {
    Person p1(18, "Tom");
    Person p2(20, "Jake");

    if(func(p1, p2))
        cout << "the ages are same" << endl;
    else
        cout << "It's different" << endl;

    return 0;
}

重载成员函数

#include <iostream>
#include <string.h>
using namespace std;

/*
函数调用重载运算符*/
//使用非常灵活

class Print {
  public:
    void operator()(string context) {
        cout << context << endl;
    }
};

class Add {
  public:
    int operator()(int num1, int num2) {
        return num1 + num2;
    }
};

int main() {
    Print p;
    //和函数使用非常像,也称为仿函数
    p("Hello world");

    Add a;
    cout << a(5, 2) << endl;

    //使用匿名对象,执行完立即消失
    cout << Add()(100, 100) << endl;
    return 0;
}

/*
Hello world
7
200
*/

5) 继承

继承方式的特点

在这里插入图片描述

继承对象模型

#include <iostream>
#include <string.h>
using namespace std;

/*
继承*/
//所有的都被继承了,即使是基类中的private
class Base {
  public:
    int a;

  protected:
    int b;

  private:
    int c;
};

class Son1 : public Base {
  private:
    int d;
};

int main() {
    Son1 s;
    cout << "the size of s " << sizeof(s) << endl;

    return 0;
}

/*
16
*/

构造和析构的顺序

#include <iostream>
#include <string.h>
using namespace std;

/*
继承*/
//所有的都被继承了,即使是基类中的private
class Base {
  public:
    int a;
    Base() {
        cout << "Base 构造函数" << endl;
    }
    ~Base() {
        cout << "Base 析构函数" << endl;
    }

  protected:
    int b;

  private:
    int c;
};

class Son1 : public Base {
  public:
    Son1() {
        cout << "Son1 构造函数" << endl;
    }
    ~Son1() {
        cout << "Son1 析构函数" << endl;
    }

  private:
    int d;
};

int main() {
    Son1 s;
    return 0;
}

/*
Base 构造函数
Son1 构造函数
Son1 析构函数
Base 析构函数
*/

继承同名的处理方式

#include <iostream>
#include <string.h>
using namespace std;

/*
继承*/
// 同名时编译器会隐藏基类中的所有同名属性或者函数
class Base {
  public:
    int a = 100;
    void func() {
        cout << "Base func函数调用" << endl;
    }

  protected:
    int b;

  private:
    int c;
};

class Son1 : public Base {
  public:
    int a = 200;
    void func() {
        cout << "Son1 func函数调用" << endl;
    }

  private:
    int d;
};

int main() {
    Son1 s;
    cout << s.a << endl;
    //同名时想要访问到基类中的成员变量,加上作用域
    cout << s.Base::a << endl;

    //函数的同名
    s.func();
    s.Base::func();

    return 0;
}

同名静态成员的处理方式

#include <iostream>
#include <string.h>
using namespace std;

/*
继承*/
// 同名时编译器会隐藏基类中的所有同名属性或者函数
class Base {
  public:
    //类内声明
    static int a;
};

int Base::a = 100;

class Son1 : public Base {
  public:
    static int a;
};

int Son1::a = 200;

int main() {
    Son1 s;
    //通过对象访问
    cout << s.a << endl;
    //同名时想要访问到基类中的成员变量,加上作用域
    cout << s.Base::a << endl;

    //通过类名访问
    cout << Son1::a << endl;
    cout << Son1::Base::a << endl;

    return 0;
}

/*
静态函数也是一样的
*/

多继承语法

#include <iostream>
#include <string.h>
using namespace std;

/*
继承*/
// 同名时编译器会隐藏基类中的所有同名属性或者函数
class Base1 {
  public:
    //类内声明
    static int a;
};

int Base1::a = 100;

class Base2 {
  public:
    int b;
};

class Son1 : public Base1, public Base2 {
  public:
    static int a;
};

int Son1::a = 200;

int main() {
    Son1 s;
    cout << sizeof(s) << endl;

    return 0;
}

/*
语法: class 子类: 继承方式:基类,继承方式,基类
多继承容易出现同名问题,使用的时候说明作用域就好
*/

虚继承解决菱形继承问题

/*
继承*/
class Animal {
  public:
    int Age;
};

class Sheep : public Animal {
  public:
    Sheep() {
        Age = 10;
    }
};

class Camel : public Animal {
  public:
    Camel() {
        Age = 3;
    }
};

class Caonima : public Sheep, public Camel {
};

// 为了解决多余继承问题
//使用虚继承

class Newone : virtual public Sheep, virtual public Camel {
};

int main() {
    Caonima c;
    cout << sizeof(c) << endl;  // 8 说明继承了两份

    Newone n;
    cout << sizeof(n) << endl;

    return 0;
}

6)多态

基本语法

#include <iostream>
#include <string.h>
using namespace std;

/*多态
1. 有继承关系
2. 派生类重写基类的函数,派生类中可写virtual也可以不写,基类必须写*/
class Animal {
  public:
    //
    // void speak() {
    //     cout << "动物在说话" << endl;
    // }
    //写成虚函数
    virtual void speak() {
        cout << "动物在说话" << endl;
    }
};

class Sheep : public Animal {
  public:
    void speak() {
        cout << "小羊在说话" << endl;
    }
};

class Camel : public Animal {
  public:
    void speak() {
        cout << "骆驼在说话" << endl;
    }
};

//执行说话的函数
//地址早帮定,在编译阶段就已经确定了函数的地址
// 如果想让不同的动物说话,就不能一开始就确定函数地址
//需要运行阶段再帮定
void doSpeak(Animal& animal) {
    animal.speak();
};

int main() {
    Sheep sheep;
    doSpeak(sheep);

    return 0;
}

计算器(案例)

#include <iostream>
#include <string.h>
using namespace std;

/*多态*/

//普通写法
class Calculator {
  public:
    void set(int a, int b) {
        n1 = a;
        n2 = b;
    }
    int Result(string oper) {
        if(oper == "+")
            return n1 + n2;
        else if(oper == "-")
            return n1 - n2;
        else if(oper == "*")
            return n1 * n2;
        return -999;  //没有符合的情况
        //如果想要添加新的功能,需要修改源码
    }

  private:
    int n1, n2;
};

//多态写法
//结构清晰
//可读性强
// 方便扩展和维护
class AbstractCalculator {
  public:
    virtual int Result() {
        return 0;
    }

    void SetValue(int a, int b) {
        n1 = a;
        n2 = b;
    }

  protected:
    int n1, n2;
};

//加法类
class AddCalculator : public AbstractCalculator {
  public:
    virtual int Result() {
        return n1 + n2;
    }
};

// 减法类
class MinusCalculator : public AbstractCalculator {
  public:
    virtual int Result() {
        return n1 - n2;
    }
};

//乘法类
class MultipleCalculator : public AbstractCalculator {
  public:
    virtual int Result() {
        return n1 - n2;
    }
};

int main() {
    Calculator c;
    c.set(10, 12);
    cout << c.Result("+") << endl;

    //多态
    // 基类的指针或者引用指向派生类对象
    AbstractCalculator* abc = new AddCalculator;
    abc->SetValue(10, 12);
    cout << abc->Result() << endl;
    //创建在堆区,记得手动释放
    delete abc;

    //现在想创建一个减法类
    // abc在堆区的空间已经被释放,但是地址依然在
    abc = new MinusCalculator;
    abc->SetValue(10, 12);
    cout << abc->Result() << endl;

    return 0;
}

纯虚函数和抽象类

#include <iostream>
#include <string.h>
using namespace std;

/*多态*/

//纯虚函数和抽象类
class Base {
  public:
    /*纯虚函数的基本语法
    只要有一个纯虚函数,这个类称为抽象类
    特点:
    1. 无法实例化对象
    2. 抽象类的派生类必须重写基类中的abstract function,不然也是继承的抽象类*/
    virtual void func() = 0;
};

class Son : public Base {
  public:
    virtual void func() {
        cout << "function of func has been used" << endl;
    }
};

int main() {
    // object of abstract class type "Base" is not allowed:
    // function "Base::func" is a pure virtual function
    //  Base s;

    Son s;
    s.func();

    return 0;
}

制作饮品(案例)

#include <iostream>
#include <string.h>
using namespace std;

/*多态*/

//纯虚函数和抽象类
class AbstractDrinking {
  public:
    virtual void Biol() = 0;

    virtual void Brew() = 0;

    virtual void PourInCup() = 0;

    virtual void PutSomthing() = 0;

    void MakeDrink() {
        Biol();
        Brew();
        PourInCup();
        PutSomthing();
    }
};

//制作coffe
class Coffee : public AbstractDrinking {
  public:
    virtual void Biol() {
        cout << "烧开农夫山泉" << endl;
    }
    virtual void Brew() {
        cout << "冲泡咖啡" << endl;
    }
    virtual void PourInCup() {
        cout << "倒入杯子中" << endl;
    }
    virtual void PutSomthing() {
        cout << "加入牛奶" << endl;
    }
};

//制作tea

class Tea : public AbstractDrinking {
  public:
    virtual void Biol() {
        cout << "烧开井水" << endl;
    }
    virtual void Brew() {
        cout << "冲泡茶叶" << endl;
    }
    virtual void PourInCup() {
        cout << "倒入杯子中" << endl;
    }
    virtual void PutSomthing() {
        cout << "加入枸杞" << endl;
    }
};

// 制作函数
void DoWork(AbstractDrinking* abs) {
    abs->MakeDrink();

    //手动清除
    delete abs;
}
int main() {
    DoWork(new Coffee);

    cout << "-----------" << endl;

    DoWork(new Tea);

    return 0;
}

虚析构和纯虚析构

#include <iostream>
#include <string.h>
using namespace std;

/*多态*/

/*1. 用于解决无法通过基类释放派生类对象
2. 如果没有堆区数据,可以不写虚析构或者纯虚析构函数
3. 有了纯虚析构那么也是虚类,不能实例化对象*/
class Animal {
  public:
    //纯虚函数
    virtual void Speak() = 0;
    Animal() {
        cout << "Animal 构造函数调用" << endl;
    }

    // ~Animal(){
    //     cout<<"Animal 析构函数调用"<<endl;
    // }

    // 1. 利用虚析构函数解决基类指针无法调用派生类的析构函数
    // virtual ~Animal(){
    //     cout<<"Animal 虚析构函数调用"<<endl;
    // }

    // 2. 利用纯虚析构
    virtual ~Animal() = 0;
};

//纯虚析构如果声明一定要实现
//另外有了纯虚析构那么也是虚类,不能实例化对象
Animal::~Animal() {
    cout << "Animal 纯虚析构函数调用" << endl;
}

class Cat : public Animal {
  public:
    virtual void Speak() {
        cout << *Name << " 小猫在说话" << endl;
    }
    //析构函数
    Cat(string name) {
        cout << "Cat 构造函数调用" << endl;
        Name = new string(name);
    }

    ~Cat() {
        if(Name) {
            cout << "Cat 析构函数调用" << endl;
            delete Name;
            Name = NULL;
        }
    }

  private:
    string* Name = NULL;
};

int main() {
    Animal* animal = new Cat("Tom");

    animal->Speak();

    //基类的指针在析构的时候无法调用派生类中的析构函数
    //导致子类如果有数据在堆中,那么就不会被释放,导致内存泄露
    delete animal;

    return 0;
}

电脑组装 (案例)

#include <iostream>
using namespace std;

/*多态*/

class CPU {
  public:
    virtual void calculator() = 0;
};

class GPU {
  public:
    virtual void display() = 0;
};

class Memory {
  public:
    virtual void storage() = 0;
};

class Computer {
  public:
    Computer(CPU* c,
             GPU* g,
             Memory* m) {
        cpu = c;
        gpu = g;
        memory = m;
    }

    //提供工作函数
    void Work() {
        //让不同的零件调用不同的借口开始工作
        cpu->calculator();
        gpu->display();
        memory->storage();
    }

    //提供析构函数释放传入的3个电脑零件
    ~Computer() {
        if(cpu) {
            delete cpu;
            cpu = NULL;
        }
        if(gpu) {
            delete gpu;
            gpu = NULL;
        }
        if(memory) {
            delete memory;
            memory = NULL;
        }
    }

  private:
    CPU* cpu = NULL;
    GPU* gpu = NULL;
    Memory* memory = NULL;
};

// Inter厂商
class InterCPU : public CPU {
  public:
    void calculator() {
        cout << "Inter 的 GPU 开始计算了" << endl;
    }
};

class InterGPU : public GPU {
  public:
    void display() {
        cout << "Inter 的 GPU 开始显示了" << endl;
    }
};

class InterMemory : public Memory {
  public:
    void storage() {
        cout << "Inter 的 Memory 开始存储了" << endl;
    }
};

// Lenovo厂商
class LenovoCPU : public CPU {
  public:
    void calculator() {
        cout << "Lenovo 的 GPU 开始计算了" << endl;
    }
};

class LenovoGPU : public GPU {
  public:
    void display() {
        cout << "Lenovo 的 GPU 开始显示了" << endl;
    }
};

class LenovoMemory : public Memory {
  public:
    void storage() {
        cout << "Lenovo 的 Memory 开始存储了" << endl;
    }
};

int main() {
    //第一台电脑的零件
    CPU* interCpu = new InterCPU;
    GPU* interGpu = new InterGPU;
    Memory* interMemory = new InterMemory;

    //创建第一台电脑
    Computer* computer = new Computer(interCpu, interGpu, interMemory);
    computer->Work();
    //释放
    delete computer;

    cout << "-------------" << endl;

    //组装第二台电脑
    Computer* computer1 = new Computer(new LenovoCPU, new LenovoGPU, new LenovoMemory);
    computer1->Work();
    delete computer1;

    cout << "-------------" << endl;
    //创建第3台电脑, 混合
    Computer* computer2 = new Computer(new InterCPU, new LenovoGPU, new InterMemory);
    computer2->Work();
    delete computer2;

    return 0;
}

6 文件

1)写

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

/*文件*/

int main() {
    ofstream ofs;
    ofs.open("file.txt", ios::out);

    ofs << "这是我想要存储在文件中的文本" << endl;
    ofs << "这个也是想要保存的" << endl;

    ofs.close();

    return 0;
}

2) 读

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

/*文件*/
int main() {
    ifstream ifs;
    ifs.open("file.txt", ios::in);

    //判断是否正确打开
    if(!ifs.is_open()) {
        cout << "文件没有正确打开" << endl;
        return 0;
    }

    //读数据
    // way 1
    // char buf[1024]={0};
    // while (ifs>>buf)
    // {
    //     cout<<buf<<endl;
    // }

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

    // way 3
    //  string buf;
    //  while(getline(ifs,buf)){
    //      cout<<buf<<endl;
    //  }

    // way 4
    char c;
    while((c = ifs.get()) != EOF) {
        cout << c;
    }

    ifs.close();

    return 0;
}

3)二进制写

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

class Person {
  public:
    char Name[64];
    int Age;
};

/*文件*/
int main() {
    // expression 1
    // ofstream ofs;
    // ofs.open("file.txt",ios::out | ios::binary);

    // expression 2
    ofstream ofs("file.txt", ios::out | ios::binary);

    Person p = {"张三", 18};

    //写入文件
    ofs.write((const char*)&p, sizeof(p));

    ofs.close();

    return 0;
}

4)二进制读

#include <fstream>
#include <iostream>
#include <string>
using namespace std;

class Person {
  public:
    char Name[64];
    int Age;
};

/*文件*/
int main() {
    ifstream ifs;

    ifs.open("file.txt", ios::in | ios::binary);

    if(!ifs.is_open()) {
        cout << "文件打开失败" << endl;
        return 0;
    }

    Person p;

    ifs.read((char*)&p, sizeof(Person));

    cout << "姓名:" << p.Name << "  年龄: " << p.Age << endl;

    ifs.close();

    return 0;
}

7 模板

1)基本语法

#include <iostream>
using namespace std;

template <typename Type>
void Swap(Type& a, Type& b) {
    Type tmp = a;
    a = b;
    b = tmp;
}

int main() {
    int a = 12;
    int b = 20;

    cout << a << "  " << b << endl;
    // 1. 自动类型推导
    Swap(a, b);
    cout << a << "  " << b << endl;

    double c = 2.345345;
    double d = 5.232423;
    cout << c << "  " << d << endl;
    // 2.  显示指定类型
    Swap<double>(c, d);
    cout << c << "  " << d << endl;

    return 0;
}

2)函数模板

没有参数时

#include <iostream>
using namespace std;

template <typename Type>
void func() {
    cout << "func 函数被调用" << endl;
}

int main() {
    //没有参数类型的话没有办法自动推导
    // func();

    //可以随便给出一个类型
    func<int>();
    func<double>();

    return 0;
}

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

#include <iostream>
using namespace std;

template <typename Type>
void func1(Type a, Type b) {
    cout << a + b << endl;
}

void func2(int a, int b) {
    cout << a + b << endl;
}

int main() {
    //整型和字符型是可以自动发生隐式转换的

    int a = 20;
    char ch = 'a';

    //无法被推导出一致的参数类型,多一报错
    // func1(a,ch);//这一句无法被运行
    //我么可以使用显式指定类型
    func1<int>(a, ch);

    func2(a, ch);

    return 0;
}

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

#include <iostream>
using namespace std;

/*调用规则
1. 如果函数模板和普通模板都可以实现那么优先调用普通函数
2.通过空模板参数列表强制调用 函数模板
3. 函数模板可以发生函数重载
4. 如果函数模板可以产生更好的匹配,那么优先调用函数模板*/

template <typename Type>
void func(Type a, Type b) {
    cout << a + b << endl;
    cout << "函数模板被调用" << endl;
}
template <typename Type>
void func(Type a, Type b, Type c) {
    cout << a + b + c << endl;
    cout << "重载函数模板被调用" << endl;
}

void func(int a, int b) {
    cout << a + b << endl;
    cout << "普通函数被调用" << endl;
}

int main() {
    //整型和字符型是可以自动发生隐式转换的

    int a = 20;
    int b = 30;

    func(a, b);  //调用普通函数

    //通过空参数列表
    func<>(a, b);

    func(a, b, 100);

    //更好的匹配举例
    char ch = 'a';
    char ar = 'd';
    func(ch, ar);  //普通函数的话还需要转换

    return 0;
}

模板的局限性

#include <cstdbool>
#include <iostream>
#include <string>
using namespace std;

class Person {
  public:
    Person(string name, int age) {
        Name = name;
        Age = age;
    }

    string Name;
    int Age;
};

template <typename Type>
bool Cmp(Type& a, Type& b) {
    if(a == b)
        return true;
    return false;
}

//解决办法
//利用具体化的版本实现,具体化优先调用
//相当于针对特殊的情况单独写,系统会自动调用
template <>
bool Cmp(Person& a, Person& b) {
    if(a.Age == b.Age && a.Name == b.Name)
        return true;
    return false;
}

int main() {
    int a = 10;
    int b = 20;

    if(Cmp(a, b))
        cout << "a==b" << endl;

    //对于自定义数据类型
    Person p1("Tom", 10);
    Person p2("Pony", 20);

    // no match for 'operator==' (operand types are 'Person' and 'Person')
    if(Cmp(p1, p2))
        cout << "p1和p2是一样的" << endl;

    return 0;
}

3) 类模板

基本语法

#include <cstdbool>
#include <iostream>
#include <string>
using namespace std;

template <class Nametype, class Agetype>
class Person {
  public:
    Person(Nametype name, Agetype age) {
        Age = age;
        Name = name;
    }
    void ShowInfo() {
        cout << Name << " and " << Age << endl;
    }

  private:
    Nametype Name;
    Agetype Age;
};

//使用默认参数
template <class Nametype, class Agetype = int>
class Person1 {
  public:
    Person1(Nametype name, Agetype age) {
        Age = age;
        Name = name;
    }
    void ShowInfo() {
        cout << Name << " and " << Age << endl;
    }

  private:
    Nametype Name;
    Agetype Age;
};

int main() {
    //指定显示类型
    Person<string, int> p1("张三", 18);

    p1.ShowInfo();

    // 1. 类模板没有自动类型推导的使用方式
    // Person p2("李四",20);

    // 2. 类模板在模板参数列表中可以有默认参数
    Person1<string> p2("李四", 20);
    p2.ShowInfo();
    return 0;
}

类模板和函数模板的区别

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

template <class Nametype, class Agetype>
class Person1 {
  public:
    Person1(Nametype name, Agetype age) {
        Age = age;
        Name = name;
    }

    void ShowInfo() {
        cout << Name << " and" << Age << endl;
    }

  private:
    Nametype Name;
    Agetype Age;
};

template <class Nametype, class Agetype = int>
class Person2 {
  public:
    Person2(Nametype name, Agetype age) {
        Age = age;
        Name = name;
    }
    void ShowInfo() {
        cout << Name << " and " << Age << endl;
    }

  private:
    Nametype Name;
    Agetype Age;
};
int main() {
    Person1<string, int> p1("Zhangsan", 19);
    p1.ShowInfo();

    //类模板没有自动类型推导,必须指定
    // Person p2("Lisi",20);

    //类模板可以在参数列表中有默认参数
    Person2<string> p2("Lisi", 30);
    p2.ShowInfo();

    return 0;
}

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

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

class Person1 {
  public:
    void ShowPerson1() {
        cout << "Person1 show" << endl;
    }
};
class Person2 {
  public:
    void ShowPerson2() {
        cout << "Person2 show" << endl;
    }
};

template <class Type>
class MyClass {
  public:
    Type obj;
    //类模板中的成员函数
    void func1() {
        obj.ShowPerson1();
    }

    void func2() {
        obj.ShowPerson2();
    }
};

int main() {
    //通过这两个来说明类模板中的成员函数并不是一开始就创建的
    // 而是调用的时候再创建
    MyClass<Person1> m;
    m.func1();
    // m.func2();

    MyClass<Person2> n;
    // n.func1();
    n.func2();

    return 0;
}

类模板对象作为函数参数

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

//先声明一个类模板
template <class T1, class T2>
class Person {
  public:
    Person(T1 name, T2 age) {
        this->Name = name;
        this->Age = age;
    }
    void ShowPerson() {
        cout << "the name: " << this->Name << " and the age is " << this->Age << endl;
    }

  private:
    T1 Name;
    T2 Age;
};

// 传入方式
// 1. 指定传入类型、
void PrintPerson1(Person<string, int>& p) {
    p.ShowPerson();
}

// 2.参数模板化
template <class T1, class T2>
void PrintPerson2(Person<T1, T2>& p) {
    p.ShowPerson();
    //其实我们也可在函数中输出程序推出的这个参数是什么类型
    cout << "T1的类型是: " << typeid(T1).name() << endl;
    cout << "T2的类型是: " << typeid(T2).name() << endl;
}

// 3. 整个类模板化
template <typename Type>
void PrintPerson3(Type& p) {
    p.ShowPerson();
    cout << "Type 的类型是: " << typeid(Type).name() << endl;
}

int main() {
    Person<string, int> p("Zhangsan", 100);
    PrintPerson1(p);
    PrintPerson2(p);
    PrintPerson3(p);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值