C++笔记

目录

      • 内存分区
          • 栈区
          • 堆区
      • 引用&
          • 起别名
          • 引用做函数参数
          • 引用做函数返回值
          • 引用的本质
          • 常量引用
      • 函数重载需要注意的
      • 类和对象
      • struct和class
      • 构造函数和析构函数
          • 构造函数
      • 深拷贝和浅拷贝
      • 初始化列表
      • A类对象作为B类的属性
      • 静态成员
      • 成员变量和成员函数分开存储
      • this指针
      • 空指针访问成员
      • const修饰成员函数
      • 友元
      • 运算符重载
          • `+`运算 符重载,实现两个自定义对象的相加
          • `<<`运算符重载
          • 实现输出一个自定义对象的各属性
          • `++`运算符重载
          • `=`运算符重载
          • 类对象`=`的重载
          • 重载函数调用`()`运算符——仿函数
      • 继承
          • 继承方式
          • 继承中对象属性大小
          • 继承中的构造和析构顺序
          • 继承同名成员函数
          • 继承同名静态成员
      • 多继承
      • 菱形继承及解决方法(虚继承)
      • 多态
          • 开闭原则
          • 多态实现计算器
      • 纯虚函数和抽象类
      • 虚析构和纯虚析构
        • 组装案例
      • 文件操作
          • 写文件
          • 读文件
          • 二进制写文件
          • 二进制读文件
      • 模版
          • 函数模版

内存分区

C++将内存划分为4个区域

  1. 代码区(程序执行前):存放函数二进制代码
  2. 全局区(程序执行前):存放全局变量、静态变量以及常量
  3. 栈区:由编译器自动分配释放,存放函数参数值,局部变量
  4. 堆区:由人分配和释放(new,delete),程序结束之后系统会回收
#include
using namespace std;

// 全局变量
int g_a = 0;
int g_b = 1;

// 全局常量
const int c_g_a = 0;


int main()
{
    // 内存分为四个区
    // 代码区,全局区,栈区,堆区

    cout<<"全局变量g_a的地址:"<<&g_a<

观察上述的地址

栈区

不要返回局部变量的地址

#include
using namespace std;

int* fun()
{
    int a = 10;
    return &a;
}

int main()
{
    int* p = fun();

    cout<<*p<
堆区

new / delete

int* fun()
{
    int* a = new int(10);//在堆区开辟一个内存,值是10,然后将其的地址赋值给指针p
    return a;
}

int main()
{
    int* p = fun();

    cout<<*p<

引用&

起别名
int a = 10;
int& b = a;
cout<<"b = "<#include
using namespace std;


// 值传递
void swap01(int a, int b)
{
    int temp = a;
    a = b;
    b = temp;
}


// 地址传递
void swap02(int* a,int* b)
{
    int temp = *a;
    *a = *b;
    *b = temp;
}

//引用传递,参数理解为起的别名
void swap03(int& a,int& b)
{
    int temp = a;
    a = b;
    b = a;
}


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

    swap01(a,b);//并没有交换两个值
    swap01(&a,&b);//成功交换
    swap03(a,b);//成功交换

    return 0;
}
引用做函数返回值
  • 函数不能返回局部变量的引用
//不能返回局部变量的引用
int& fun01()
{
    int a = 0;
    return a;
}


int main()
{

    int& ref = fun01();
    cout<
  • 函数的调用可以作为左值
// 函数的调用可以作为左值
int& fun02()
{
    static int a = 0;//静态变量,存放在全局区,在程序结束后释放
    return a;
}

int main()
{

    int& ref2 = fun02();
    cout<<"ref2 = "<int main()
{
    int a = 10;
    
    //自动转换为 int* const ref = &a; 指针常量是指向一个不可更改的常量,也说明了引用为什么不可更改
    int& ref = a;
    ref = 20;//内部发现是一个引用,自动帮我们转换为 *ref = 20;
    
    cout<<"a = "<//常量引用,用来修饰形参,防止实参被修改

// 这个函数会将外部的实参修改掉
void printValue01(int& a)
{
    a = 0;
    cout<<"value + 10 = "<#include
using namespace std;


// 函数重载需要注意的事项
void fun(int& a)// int& a = 10 不合法
{
    cout<<"fun(int& a)"<

函数重载遇到默认参数

// 函数重载遇到默认参数
void fun01(int a,int b = 10)
{
    cout<<"fun01(int a,int b = 10)"<

类和对象

#include

class Student
{
public:
    string name;
    int stuId;

    void printInfo()
    {
        cout<<"name = "<
  • public:类内可以访问,类外也可以访问
  • protected:类内可以访问,类外不可以访问,可以访问继承的父类
  • private:类内可以访问,类外不可以访问,不可以访问继承的父类

struct和class

C++中,struct和class的唯一区别就是访问权限不同

  • class 默认权限是 私有private
  • struct 默认权限是 公共public

构造函数和析构函数

构造函数和析构函数都是必须有的实现,如果不提供,编译器会提供至少3个函数:默认构造函数(空实现)、析构函数(空实现)、拷贝构造函数 (值拷贝)

如果用户定义了有参构造函数,c++不会提供无参构造函数,但是会提供拷贝构造函数

如果用户定义了拷贝构造函数,c++不会提供其它构造函数

  1. 构造函数

    可以重载

    创建对象时调用

  2. 析构函数

    不可以重载

    程序的生命周期终结时调用

#include
using namespace std;


class Person
{
public:
    Person()
    {
        cout<<"Person 构造函数"<
构造函数

3种构造的方法

class Person
{
private:
    int age;

public:
    Person()
    {
        cout<<"Person 无参函数"<age = age;
        cout<<"Person 有参构造"<age = p.age;
        cout<<"Person 拷贝构造函数"<
Person fun()
{
    Person p1;
    return p1;//这里返回的并不是p1对象,而是执行力拷贝构造函数,创建了一个新的对象
}

深拷贝和浅拷贝

浅拷贝:简单的赋值拷贝操作

深拷贝:在堆区重新申请空间,进行拷贝操作

如果有属性是在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

class Car
{
private:
    int car_id;
    double* car_value;

public:
    Car()
    {
        cout<<"无参构造函数";
    }
    Car(int id,double value)
    {
        car_id = id;
        car_value = new double(value);//在堆区new一个空间,返回一个指针
        cout<<"有参构造函数";
    }

    //自己实现拷贝构造函数,解决编译器提供的拷贝构造函数带来的浅拷贝问题
    Car(const Car& car)
    {
        car_id = car.car_id;
        //car_value = car.car_value;//编译器提供的拷贝构造函数,就是这行代码,浅拷贝
        // 深拷贝,解决car_value内存释放冲突问题
        car_value = new double(*car.car_value);
    }

    ~Car()
    {
        if (car_value != NULL)//car_value是在堆区手动创建的,需要手动释放
        {
            delete car_value;
            car_value = NULL;
        }
        cout<<"析构函数"<

初始化列表

class A
{
private:
    int A_a;
    int A_b;
    int A_c;

public:
    A(int a,int b,int c):A_a(a),A_b(b),A_c(c){}
    
};


int main()
{
    A aa(1,3,4);
    
    return 0;
}

A类对象作为B类的属性

class Phone
{
    string name;
}

class Person
{
    int id;
    Phone phone;
}
  • 构造时先构建A的对象,再构造B对象自身
  • 析构函数相反

静态成员

  1. 所有对象都共享同一份数据或函数
  2. 编译阶段就分配内存
  3. 类内声明,类外初始化
  4. 静态成员函数只能访问静态的成员变量
class A
{
 private:
    static string name;//类外访问不到
 public:
    static int id;
    
    static void fun()
    {
        cout<

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

空对象占用的内存空间为 1

编译器会给每个空对象分配 1 个字节空间,为了区分空对象占内存的地址,每个空对象也应该有一个独一无二的内存地址

class A
{
    
};

int main()
{
    A a;//空对象 sizeof(a) = 1
}



class B
{
    int aa;//属于类的对象
    static int bb;//不属于类的对象
    void fun();//不属于类的对象
};

int main()
{
    B b;//sizeof(b) = 4
}

this指针

  • 解决命名冲突
  • 返回对象本身 *this
class Person
{
    int age;
    Person(int age)
    {
        this->age = age;//this指针解决命名冲突
    }
    
    Person& addAge01(Person& p)//返回 引用
    {
        this->age += p.age;
        return *this;//返回对象本体
    }
    
    Person addAge02(Person& p)//返回 值
    {
        this->age += p.age;
        return *this;//返回一个新的对象(调用拷贝构造函数)
    }
    
};

空指针访问成员

class Phone
{
    int age;
    void showClass()
    {
        cout<"this is class Phone";
    }
    void showAge()
    {
        if (this == NULL)
        {
            return;
        }
        cout<<"age is "<age
    }
}

int main()
{
    Phone* p = NULL;
    phone.showClass();//正常执行
    phone.showAge();//报错 空指针异常
    return 0;
}

const修饰成员函数

常函数

  • 常函数不可以修改成员属性
  • 成员属性声明时加 mutable,在常函数中就可以修改
class A
{
    //this指针本质是一个指针常量,指针的指向是不可修改的
    //后面加const,意味着指针指向的值也不可以修改
    void showA() const
    {
        //this->age = 10;//会报错,this指针不可以修改
        this->id = 1;//正常执行      
    }
    int age;
    mutable id;//特殊变量,在常函数和常对象中可以修改
}

常对象

  • 声明对象前加 const

  • 常对象只能调用常函数

void fun()
{
    const Person p;//在对象前加const,变为常对象
    //p.age = 10;//错误,不能被修改
    p.id = 1;//正确,可以修改
    
    p.showA();//正确,可以执行 
}

友元

全局函数作友元,可以访问类的私有成员

 #include
 #include
 using namespace std;


class Home
{
    //声明全局函数friend_fun是一个友元,就可以访问Home中的的私有成员
    friend void friend_fun(Home* home);

public:

    Home()
    {
        this->sitting_room = "客厅";
        this->bad_room = "卧室";
    }

    string sitting_room;


private:
    string bad_room;
};

void friend_fun(Home* home)
{
    cout<<"公共属性 "<sitting_room<bad_room<

作友元

class TV
{
public:
    Home* home;
    
    TV()
    {
        this->home = new Home;
    }
}

class Home
{
	//类作友元,
	friend class TV;

public:
    Home()
    {
        this->sitting_room = "客厅";
        this->bad_room = "卧室";
    }
    string sitting_room;

private:
    string bad_room;
};

成员函数作友元

class TV
{
private:
        Home* home;

public:   
    void visit01()
    {
        cout<sitting_room<bad_room<sitting_room<bad_room<sitting_room = "客厅";
        this->bad_room = "卧室";
    }
    string sitting_room;

private:
    string bad_room;
};

运算符重载

+运算 符重载,实现两个自定义对象的相加
  • 成员函数重载
  • 全局函数重载
#include
using namespace std;

class Person
{
public:
    Person(){}

    Person(int a,int b)
    {
        this->m_a = a;
        this->m_b = b;
    }

    // 1 成员函数重载 + 运算符
    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;
};



// 2 全局函数重载 + 运算符
Person operator+(Person& p1,Person& p2)
{
    Person p3;
    p3.m_a = p1.m_a + p2.m_a;
    p3.m_b = p1.m_b + p2.m_b;
    
    return p3;
}

//函数重载的版本
Person operator+(Person& p,int num)
{
    Person p3;
    p3.m_a = p.m_a + num;
    p3.m_b = p.m_b + num;
    
    return p3;
}



int main()
{
//实现两个自定义数据类型相加的运算
    Person p1 = Person(2,3);
    Person p2 = Person(10,20);

    Person p3 = p1 + p2;
    
    Person p4 = p1 + 99;

    cout<<"p3.m_a = "<class Person
{
    friend ostream& operator<<(ostream& out,Person p);

public:
    Person(){}

    Person(int a,int b)
    {
        this->m_a = a;
        this->m_b = b;
    }

private:
    int m_a; 
    int m_b;
};


//只能用全局函数实现 重载<<运算符
ostream& operator<<(ostream& out,Person p)
{
    out<<"m_a = "<#include
using namespace std;

class MyInteger
{
    friend ostream& operator<<(ostream& out,MyInteger myint);


public:
    MyInteger(){}

    MyInteger(int m)
    {
        this->m_num = m;
    }


    //重载 前置++ 运算符
    MyInteger& operator++()//用MyInteger& 是为了对自身进行返回,一直对一个数据进行++
    //如果 用MyInteger,则会新创建一个MyInteger对象
    {
        //先进行++运算
        this->m_num++;
        // 在将自身返回
        return *this;
    }


    //重载 后置++ 运算符
    MyInteger operator++(int)//int表示站位参数,可以用于区分前置和后置
    {
        // 先记录最开始的值
        MyInteger temp = *this;
        // 再递增
        this->m_num++;
        // 返回最开始的值
        return temp;//局部对象,只能返回值,不能返回引用
    }
private:
    int m_num;
};


// 重载<<运算符
    ostream& operator<<(ostream& out,MyInteger myint)
    {
        out<
=运算符重载
#include
using namespace std;

class Person
{

public:
    int* m_age;

    Person(){}

    Person(int age)
    {
        this->m_age = new int(age);
    }

    ~Person()
    {
        if (this->m_age != NULL)
        {
            delete this->m_age;
            this->m_age = NULL;
        }
    }


    Person& operator=(Person& p)
    {
        //编译器提供浅拷贝,会出现内存释放冲突
        //this->m_age = p.m_age;

        //1 应该先判断是否有属性在堆区,如果有,先释放干净,然后再深拷贝
        if (this->m_age != NULL)
        {
            delete this->m_age;
            this->m_age = NULL;
        }

        //深拷贝
        this->m_age = new int(*p.m_age);

        return *this;
    }
};


int main()
{

    Person p1(20);

    Person p2;
    p2 = p1;
    cout<<"p2 = "<<*p2.m_age<
类对象=的重载
#include
#include
using namespace std;


class Person
{
public:
    Person(int age,string name)
    {
        this->m_age = age;
        this->m_name = name;
    }

    //重载两个对象的关系运算符
    bool operator==(Person& p)
    {
        if (this->m_age == p.m_age && this->m_name==p.m_name)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    bool operator!=(Person& p)
    {
        if (this->m_age == p.m_age && this->m_name==p.m_name)
        {
            return false;
        }
        else
        {
            return true;
        }
    }

    int m_age;
    string m_name;
};


int main()
{
    Person p1(20,"zhangsan");
    Person p2(20,"zhangsan");

    if (p1 == p2)
    {
        cout<<"p1和p2 相等"<
重载函数调用()运算符——仿函数
#include
#include
using namespace std;

class printClass
{
public:
    // 重载函数调用()
    void operator()(string s)
    {
        cout<

继承

降低代码重复

父类:基类

子类:派生类

#include 
using namespace std;

class Page
{
public:
    void header()
    {
        cout << "页面头部内容。。" << endl;
    }
    void footer()
    {
        cout << "页面尾部内容。。" << endl;
    }
};

// 继承
class BuyPage : public Page
{
public:
    void content()
    {
        cout << "购买页面" << endl;
    }
};

class Browse : public Page
{
public:
    void content()
    {
        cout << "浏览页面" << endl;
    }
};

int main()
{
    BuyPage buy;
    buy.header();
    buy.footer();
    buy.content();

    Browse browse;
    browse.header();
    browse.footer();
    browse.content();

    return 0;
}
继承方式

C++笔记_第1张图片

#include 
using namespace std;

class Father
{
public:
    int m_a = 1;

protected:
    int m_b = 2;

private:
    int m_c = 3;
};

class Son01 : public Father
{
public:
    void test01()
    {
        cout << m_a << endl; // 公共
        cout << m_b << endl; // 保护
        // cout<
继承中对象属性大小

父类中的所有非静态成员属性都会被子类继承下去,只是某些属性的权限不同

class Father
{
public:
    int m_a = 1;

protected:
    int m_b = 2;

private:
    int m_c = 3;
};

class Son04 : public Father
{
public:
    int m_d = 0;
};

void test()
{
    //私有成员也被继承了,只是访问不到而已
    cout << "size of : "<
继承中的构造和析构顺序
  • 先构造父类,再构造子类
  • 析构顺序相反
class Base
{
    Base()
    {
        cout<<"Base 构造函数。。"<
继承同名成员函数
  • 访问子类同名成员函数,直接访问即可
  • 访问父类同名成员函数,需要加作用域
  • 如果子类中出现和父类同名的成员函数,子类的同名成员会隐藏掉父类中所有的同名成员函数(包括重载的),需要加作用域
class Base
{
    Base()
    {
        int m_a = 100;
    }
    
public:
    print_hh()
    {
        cout<<"Base: hh"<
继承同名静态成员

子类,直接访问

父类,加作用域

class Base
{
public:
    static int s_a;
    static void fun()
    {
        cout << "Base--fun()" << endl;
    }
};
int Base::s_a = 10;

class Son : public Base
{
public:
    static int s_a;
    static void fun()
    {
        cout << "Son--fun()" << endl;
    }
};
int Son::s_a = 20;

void test01()
{
    Son s;
    // 通过对象访问
    cout << s.s_a << endl;       // 20
    cout << s.Base::s_a << endl; // 10
    s.fun();                     // Son--fun()
    s.Base::fun();               // Base--fun()

    // 通过类名访问
    cout << Son::s_a << endl;       // 20
    cout << Son::Base::s_a << endl; // 10
    Son::fun();
    Son::Base::fun();
}

多继承

class Base1
{
public:
    Base1()
    {
        m_a = 1;
    }
    int m_a;
};

class Base2
{
public:
    Base2()
    {
        m_a = 2;
    }
    int m_a;
};

class Son : public Base1, public Base2
{
public:
    Son()
    {
        m_b = 3;
        m_c = 4;
    }
    int m_b;
    int m_c;
};

void test()
{
    Son s;
    cout << "size of : " << sizeof(s) << endl; // 16

    // 不建议用多继承,因为会出现二义性,必须加作用域用于区分
    cout << "Base1 :" << s.Base1::m_a << endl; // 1
    cout << "Base2 :" << s.Base2::m_a << endl; // 2
}

菱形继承及解决方法(虚继承)

两个派生类继承同一个基类,又有某个类同时继承两个派生类

	 A
   /   \
   B   C
   \   /
     D
#include 
using namespace std;

class Animal
{
public:
    Animal()
    {
        m_age = 0;
    }
    int m_age;
};

// 虚继承
class Sheep : virtual public Animal
{
public:
    Sheep()
    {
        m_age = 10;
    }
};

// 虚继承
class Tuo : virtual public Animal
{
public:
    Tuo()
    {
        m_age = 20;
    }
};

class SheepTuo : public Sheep, public Tuo
{
};

int main()
{
    SheepTuo st;
    // cout<

多态

虚函数,地址晚绑定,在运行阶段绑定函数地址,如果要实现多态,就需要使用虚函数virtual,如果不加virtual,地址早绑定,在编译阶段确定函数地址

动态多态满足条件

  • 有继承关系
  • 子类重写父类的虚函数
#include 
using namespace std;

class Animal
{
public:
    //虚函数,地址晚绑定,在运行阶段绑定函数地址,如果要实现多态,就需要使用虚函数virtual
    //如果不加virtual,地址早绑定,在编译阶段确定函数地址
    virtual void speak()
    {
        cout << "animal speaking" << endl;
    }
};

class Cat : public Animal
{
public:
    void speak()
    {
        cout << "cat speaking" << endl;
    }
};

class Dog : public Animal

{
public:
    void speak()
    {
        cout << "dog speaking" << endl;
    }
};

void dospeaking(Animal &animal)
{
    animal.speak();
}

int main()
{
    Cat cat;
    // dospeaking(cat); // animal speaking(Animal类中的speak()不加virtual)
    dospeaking(cat); // cat speaking

    Dog dog;
    dospeaking(dog); // dog speaking

    return 0;
}
开闭原则
  • 对扩展进行开放
  • 对修改进行关闭
多态实现计算器
  • 可读性好
  • 维护性高
#include 
using namespace std;

class AbstractCalcuator
{
public:
    virtual int getResult()
    {
        return 0;
    }
    int number01;
    int number02;
};

class AddCalcuator : public AbstractCalcuator
{
public:
    int getResult()
    {
        return number01 + number02;
    }
};

class SubCalcuator : public AbstractCalcuator
{
public:
    int getResult()
    {
        return number01 - number02;
    }
};

class MulCalcuator : public AbstractCalcuator
{
public:
    int getResult()
    {
        return number01 * number02;
    }
};

int main()
{
    // 实现多态的条件
    // 父类指针或引用指向子类对象
    AbstractCalcuator *cal = new AddCalcuator; // 在堆区创建对象
    cal->number01 = 10;
    cal->number02 = 20;
    cout << "number01 + number02 = " << cal->getResult() << endl;
    // cal指向堆区对象,用完要释放
    delete cal;

    cal = new SubCalcuator; // 在堆区创建对象
    cal->number01 = 10;
    cal->number02 = 20;
    cout << "number01 - number02 = " << cal->getResult() << endl;
    // cal指向堆区对象,用完要释放
    delete cal;

    cal = new MulCalcuator; // 在堆区创建对象
    cal->number01 = 10;
    cal->number02 = 20;
    cout << "number01 * number02 = " << cal->getResult() << endl;
    // cal指向堆区对象,用完要释放
    delete cal;

    return 0;
}

纯虚函数和抽象类

  • 抽象类无法实例化对象

  • 子类必须重写纯虚函数,负责也属于抽象类

#include 
using namespace std;

class Base
{
public:
    virtual void fun() = 0;
};

class Son : public Base
{
public:
    void fun()
    {
        cout << "fun()函数正在调用。。" << endl;
    }
};

int main()
{
    Base *base = new Son;
    base->fun();

    return 0;
}

虚析构和纯虚析构

问题:多态使用时,如果有子类的属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码

解决:将父类中的析构函数改为虚析构或者纯虚析构

虚析构或纯虚析构是用来解决父类指针释放子类对象

如果子类没有堆区数据,可以不写虚析构或纯虚析构

拥有纯虚析构函数的类也属于抽象类

#include 
#include 
using namespace std;

class Animal
{
public:
    Animal()
    {
        cout << "Animal构造函数" << endl;
    }
    // 利用虚析构,可以解决 父类指针释放子类对象时不干净的问题
    virtual ~Animal()
    {
        cout << "Animal析构函数" << endl;
    }
    virtual void eat() // 多态的实现条件
    {
        cout << "animal eating..." << endl;
    }
};

class Cat : public Animal
{
public:
    Cat(string name)
    {
        m_name = new string(name); // 堆区创建一个变量
        cout << "Cat构造函数" << endl;
    }
    ~Cat()
    {
        if (m_name != NULL)
        {
            delete m_name;
            m_name = NULL;
            cout << "Cat析构函数" << endl;
        }
    }
    string *m_name; // 一个指针类型的属性

    void eat()
    {
        cout << *m_name << " eating..." << endl;
    }
};

int main()
{

    Animal *animal = new Cat("Tom");
    animal->eat();
    // 父类指针在析构时,不会调用子类的析构函数,导致如果子类有堆区属性,没有成功释放,出现内存泄露
    delete animal;
    return 0;
}

纯虚析构

也是一个抽象类,无法实例化对象

#include 
#include 
using namespace std;

class Animal
{
public:
    Animal()
    {
        cout << "Animal构造函数" << endl;
    }
    // 纯虚析构,类外必须实现
    virtual ~Animal() = 0;
    virtual void eat() // 多态的实现条件
    {
        cout << "animal eating..." << endl;
    }
};
 
Animal::~Animal()
{
    cout<<"Animal析构函数"<eat();
    // 父类指针在析构时,不会调用子类的析构函数,导致如果子类有堆区属性,没有成功释放,出现内存泄露
    delete animal;
    return 0;
}
组装案例
#include 
using namespace std;

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

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

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

class Computer
{
public:
    Computer(CPU *cpu, Mermory *mermory, VideoCard *videocard)
    {
        m_cpu = cpu;
        m_mermory = mermory;
        m_videocard = videocard;
    }

    void work()
    {
        m_cpu->calculate();
        m_mermory->storage();
        m_videocard->display();
    }

    ~Computer()
    {
        if (m_cpu == NULL)
        {
            delete m_cpu;
            m_cpu = NULL;
        }
        if (m_mermory == NULL)
        {
            delete m_mermory;
            m_mermory = NULL;
        }
        if (m_videocard == NULL)
        {
            delete m_videocard;
            m_videocard = NULL;
        }
    }

private:
    CPU *m_cpu;
    Mermory *m_mermory;
    VideoCard *m_videocard;
};

class IntelCPU : public CPU
{
public:
    void calculate()
    {
        cout << "Intel cpu working.." << endl;
    }
};
class LenovoCPU : public CPU
{
public:
    void calculate()
    {
        cout << "Lenovo cpu working.." << endl;
    }
};
class IntelMermory : public Mermory
{
public:
    void storage()
    {
        cout << "Intel mermory working.." << endl;
    }
};
class LenoveMermory : public Mermory
{
public:
    void storage()
    {
        cout << "Lenovo mermory working.." << endl;
    }
};
class IntelVideoCrad : public VideoCard
{
public:
    void display()
    {
        cout << "Intel videocard working.." << endl;
    }
};
class LenovoVideoCrad : public VideoCard
{
public:
    void display()
    {
        cout << "Lenovo videocard working.." << endl;
    }
};

int main()
{
    // 组装一台电脑
    CPU *cpu01 = new IntelCPU;
    Mermory *mermory01 = new IntelMermory;
    VideoCard *videocard01 = new IntelVideoCrad;

    Computer *computer01 = new Computer(cpu01, mermory01, videocard01);
    computer01->work();
    delete computer01;

    Computer *computer02 = new Computer(new LenovoCPU, new LenoveMermory, new LenovoVideoCrad);
    computer02->work();
    delete computer02;

    return 0;
}

文件操作

  • 文本文件:以文本的ASCII码形式存储在计算机上
  • 二进制文件:以二进制形式存储在计算机上
写文件
#include 
#include 
using namespace std;

int main()
{
    // 创建写文件流对象
    ofstream ofs;
    // 指定打开文件的方式
    ofs.open("test01.txt", ios::out);
    // 写内容
    ofs << "姓名:张三" << endl;
    ofs << "性别:男" << endl;
    ofs << "年龄:100" << endl;
    ofs << "今天是2023年11月8日。。。" << endl;
    // 关闭流对象
    ofs.close();

    return 0;
}
读文件
#include 
#include 
using namespace std;

int main()
{
    // 创建读文件流对象
    ifstream ifs;
    // 读取文件
    ifs.open("test01.txt", ios::in);
    if (!ifs.is_open())
    {
        cout << "文件打开失败!!" << endl;
    }

    // 第一种
    // char buffer[1024] = {0};
    // while (ifs >> buffer)//按行读取
    // {
    //     cout << buffer << endl;
    // }

    // 第二种
    // char buffer[1024] = {0};
    // while (ifs.getline(buffer, sizeof(buffer))) // 每次按行读取存储在buffer中,每次最大读取sizeof()
    // {
    //     cout << buffer << endl;
    // }

    // 第三种
    // string buffer;
    // while (getline(ifs, buffer))
    // {
    //     cout << buffer << endl;
    // }

    // 第四种
    char c;
    while ((c = ifs.get()) != EOF) // 逐个字符读取,EOF是文件末尾的标志
    {
        cout << c;
    }

    // 流关闭
    ifs.close();

    system("pause");
    return 0;
}
二进制写文件
#include 
#include 
using namespace std;

class Person
{
public:
    char name[100];
    int age;
};

int main()
{
    // 创建流对象
    ofstream ofs("test02.txt", ios::out | ios::binary);
    // 打开文件
    // ofs.open("test02.txt",ios::out|ios::binary);

    // 写文件
    Person perosn = {"james", 40};
    ofs.write((const char *)&perosn, sizeof(Person));

    ofs.close();

    return 0;
}
二进制读文件
#include 
#include 
using namespace std;

class Person
{
public:
    char name[100];
    int age;
};

int main()
{
    // 创建读文件对象
    ifstream ifs;
    ifs.open("test02.txt", ios::in | ios::binary);
    if (!ifs.is_open())
    {
        cout << "文件打开时失败!!" << endl;
    }
    // 读文件
    Person person;
    ifs.read((char *)&person, sizeof(Person));
    cout << "name: " << person.name << ", age: " << person.age << endl;

    ifs.close();

    system("pause");
    return 0;
}

模版

泛型编程

函数模版,类模版

函数模版
  • 自动类型推导必须推导出一致的数据类型

  • 模版必须要确定出T的数据类型

#include 
using namespace std;

// 模版函数
template 
void mySwap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

template 
void printInfo()
{
    cout << "it's great!" << endl;
}

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

    // 1 自动类型推导
    mySwap(a, b);
    cout << "a = " << a << endl; // 20
    cout << "b = " << b << endl; // 10

    // 2 显式指定类型
    mySwap(a, b);
    cout << "a = " << a << endl; // 10
    cout << "b = " << b << endl; // 20

    
    
    // 自动类型推导必须要推导出正确的类型
    char c = 'q';
    // mySwap(a,c);//错误的

    // 模版必须要确定出T的类型
    //  printInfo();//错误的
    printInfo(); // 必须显式指定

    system("pause");
    return 0;
}

例子

#include 
using namespace std;

// 交换两个值的模版函数
template 
void my_swap(T &a, T &b)
{
    T temp = a;
    a = b;
    b = temp;
}

// 降序排序的模版函数
template 
void sortArr(T arr[], int len) // 降序
{
    int i = 0;
    while (i < len)
    {
        int max_idx = i;
        for (int j = i + 1; j < len; j++)
        {
            if (arr[j] > arr[max_idx])
            {
                max_idx = j;
            }
        }
        if (max_idx != i)
        {
            my_swap(arr[max_idx], arr[i]);
        }
        i++;
    }
}

//打印不同类型数组的模版函数
template 
void printArr(T arr[], int len)
{
    int i = 0;
    while (i < len)
    {
        cout << arr[i];
        i++;
    }
    cout << endl;
}

int main()
{
    char charArr[] = "efcsab";
    int lens01 = sizeof(charArr) / sizeof(char);
    sortArr(charArr, lens01);
    printArr(charArr, lens01);

    int intArr[] = {2, 4, 6, 3, 0, 9, 3, 8};
    int lens02 = sizeof(intArr) / sizeof(int);
    sortArr(intArr, lens02);
    printArr(intArr, lens02);

    system("pause");
    return 0;
}

你可能感兴趣的:(c++,笔记)