• C++


    C++面向过程

    一、Hello World

    #include <iostream>
    #defind day 7 // 宏常量
    using namespace std;
    int main(){
       // 常量,无法修改
       const int a =10;
       // 标识符区分大小写
       int A = 30;
       cout<<"hello world"<<endl;
       return 0;
    }

    二、数据类型

    2.1 基本类型

    数据类型占用空间
    short 2字节
    int 4字节
    long windows 4字节 linux 4字节(32位)8字节(64位)
    long long 8字节
    float 4字节
    double 8字节
    char 1字节
    bool 1字节
    bool 1字节

    sizeof(数据类型or变量)获取数据类型占用内存空间大小

    cout<<"语句"<<endl;

    cin>>变量>>endl;

    goto FLAG;

    FLAG:xxxx

    system("命令");

    2.1 数组

    数组是内存中一块连续空间,数组名称是数组首地址

    元素数据类型 数组名称[] = {元素1,元素2....}


    int arr[] = {1,2,3};
    // 输出元素个数
    cout>>sizeof(arr)/sizeof(arr[0])<<endl;
    // 二维数组第二个参数不能省略,2行3列
    int arr[][3]={1,2,3,4,5,6}
    // 行数
    cout<<sizeof(arr)/sizeof(arr[0])<<endl;
    // 列数
    cout<<sizeof(arr[0])/sizeof(arr[0][0])<<endl;

    2.2 指针

    指针在32位操作系统占4字节空间,在64位操作系统占8字节空间

    // 空指针,指向编号为0地址,没有访问权限
    int * p = NULL;
    // 野指针,指向非法内存空间(不是当前程序分配内存空间)
    int * p = (int *)0x1100;
    // 常量指针,指针修饰的变量可以改变指向,但是无法改变指针的值
    const int * p = &a;
    // 指针常量,指针指向不可以改,但是指针的值可以改
    int * const p = &a;
    // 将a地址复制一份传给p
    void fun(int* p){
       
    }
    fun(&a);
    // 在C语言中有void * 指针(万能指针)而C++中取消了
    int a = 10;
    void * p = &a;
    // 万能指针可以引用任何地址,但使用时需要转换到实际类型
    *(*int)p = 10;
    // 指针数组,数组每一个元素都是一个指针
    int * arr[3] = {&a,&b,&c};
    // 可以通关指针修改常量值
    const int a = 10;
    int * p = &a;
    *p=20;

    指针变量只能进行加减操作,加减单位是存储地址中存储的实际类型占用的内存空间值

    函数不要返回局部变量地址,因为函数调用完成会销毁,局部变量第二次调用会销毁

    2.3 函数

    函数定义在使用之后,则函数一定要先声明再调用,声明可以多次,定义只能一次。 声明函数可以给默认参数。 函数声明时可以不写形参,只写类型,就是占位参数。 函数在类外部也支持重载,同一作用域,函数名称相同,参数类型。 函数重载可以通过const区别

    返回值类型 函数名 (参数类列表){
       函数体语句;....
       return 返回值或表达式;
    }

    // 防止头文件重复包含
    #pragma once
    // 从c++指定类库加载
    #include<iostream>
    #include“io.h”
    // 终止函数执行
    exit(0);

    函数分文件编写:.h文件写函数声明和引用其它类库 .cpp文件写函数定义和声明函数的.h文件

    2.4 结构体

    函数参数是结构体,建议用引用传递,如果是值传递则会复制一份相同的结构体,如果是引用传递则只会复制一份地址值;防止在函数中修改结构体值,可以用常量结构体指针

    struct 结构体名{
       成员列表...
    } [变量名];

    // 结构体指针通过->符号访问结构体变量的值
    struct studet{
       string name;
       int age;
    } *p;
    cout<<p->name<<endl;
    // 为结构体赋值
    struct student = {"cai",12};
    // 防止在函数中修改结构体变量.并且引用传递不会复制结构体副本,只会复制地址值,减少内存占用
    void func(const student * stu){
       
    }

    2.5 共用体

    不能在定义共用体初始化,不能用共用体变量作为函数参数,可以用共用体指针作为参数,也可以定义共用体数组

    union 共用体类型{
       成员变量...
    }[变量名];

    2.6 枚举

    对枚举元素做常量处理,不能进行赋值,默认有序0,1,2,3....,可以用来比较

    enum week {sun,mon};

    C++面向对象

    一、内存分区模型

    • 代码区:存放函数二进制代码,由操作系统管理,是共享只读的

    • 全局区:存放全局变量和静态变量(static修饰)以及全局常量,程序结束后由操作系统自动释放(const局部常量和局部变量放在一起)

    • 栈区:编译器自动释放,存储函数参数值、局部变量等

    • 堆区:程序员分配和释放,若不释放,则在程序结束后自动释放

    通过 new 可以在堆上分配内存,通过指针引用(指针变量在栈上分配),通过 delete 删除堆空间内存

    通过typeid()返回类型

    int a[] = new int[10];
    delete[] a;
    // 创建引用变量
    int a = 10;
    // 相当于a的别名,引用必须初始化,且初始化后不可改变
    int &b = a;
    int c = 20;
    // 并不是改变应用是改变b和a的值
    b = a;
    // 引用传递使用的是原值,而不是原值的拷贝
    void func(int &a){
       
    }
    func(a);

    // 返回值是引用可以作为左值
    int& func(){
       // static 修饰变量放在常量区,防止函数返回后清除
       static int a = 20;
       return a;
    }
    func() = 30;
    // 引用本质上是指针常量,一旦初始化不能改变
    // 等价于 int const * ref = &a;
    int &ref = a;
    // 等价于 *ref = 10;
    ref = 10;
    // 引用值必须是一个合法内存空间,不能是值常量
    const int &a = 10;
    // 在堆区分配内存
    int a = new int(10);

    二、面向对象

    public:类内外都可访问 protected:类外不可访问,子类可以访问父类 private:类外不可访问,子类不可访问(默认)

    编译器提供 构造函数析构函数 默认是空,创建对象系统自动调用 构造函数,对象销毁钱自动调用 析构函数

    C++返回值如果是对象值,则会返回对象的浅拷贝(与原对象变量地址不同),值传递参数,返回值参数,使用对象初始化另外一个对象会默认调用拷贝构造函数 C++为每个空对象分配一个字节的空间,为了区分空对象占用独一无二的内存空间,如果不是空,则会占用成员变量的空间大小 this隐含在每一个非静态函数 c++给一个类添加四个默认函数:默认构造函数默认析构函数默认拷贝构造函数赋值运算符重载;当用另外一个同类对象初始化对象时调用的是拷贝构造函数;初始化之后通过=赋值对象调用的是 赋值运算符重载

    // 构造函数,可以有参数可以重载
    类名(){}
    // 析构函数,无参数不可重载
    ~类名(){}
    //拷贝构造函数
    类名()}{}

    浅拷贝带来的问题是在析构函数中对堆区内存重复释放

    class Person{
       public:
       // 为a、b指定初始值
       Person(int a,int b):m_a(a),m_b(b){
           m_a  =  new int(a);
           m_b = new int(b);
      }
       Person(int a){
           this->m_a=a;
    }
       int m_a;
       int m_b;
       ~Person(){
           delete m_a;
           delete m_b;
      }
       static int m_c;
       static void func(){
          // 防止空指针
           if(NULL==this){
               return;
          }
           // 属性前面默认加上this
           m_c = 10;
           cout<<"静态方法调用"<<endl;
      }
       void say(){
           cout<<"静态方法调用"<<endl;
      }
    }
    int main(){
       Person p(1,2);
       // 访问静态函数
       p.func();
       Person::func();
       return 0;
       // 8字节,static成员变量放在静态区
       cout<<sizeof(p)<<endl;
       Person *person = NULL;
       person->say();
    }

    const修饰成员函数叫 常函数 常函数不能修改成员属性值,成员属性加上mutable后可以被常函数修改,const修饰的对象叫做 常对象 只能调用 常函数

    class Person{
       public:
       mutable int m_A;
       int m_B;
       // this指针指向的值不可修改,即m_B不可修改
       void showPerson () const{
           this->m_A=10;
      }
       void say () {
           cout<<1<<endl;
      }
    }
    void main(){
       const Person p;
       // 常对象可以调用常函数,但是不能调用普通函数,因为普通函数会改变属性值
       p.showPerson();
    }

    友元:让一个函数或者类访问另一个函数的私有成员

    • 全局函数做友元

    class Student{
       // 友元函数是全局函数,不被类内的任何修饰符限制(即使有)
       // 类内声明,类外定义
    friend void say*(Student *stu);
       // 类内声明定义,全局函数
       friend void info(){
           cout<<"info"<<endl;
      }
    private:
       int m_Age;    
    }
    void say(Student *stu){
       cout<<stu->m_Age<<endl;
    }
    void main(){
       Student stu;
       stu.say(&stu);
    }
    • 类做友元

    // 声明类
    #include<iostream>
    #include<string>
    using namespace std;
    class Teacher;
    class Student{
       // 友元类可以访问当前类私有成员
    friend class Teacher;
    private:
       string m_Name;
       int m_Age;
       public:
       Student();
       void say();
    }
    // 类外定义构造函数
    Student::Student(){
       m_Name = "张三";
       m_Age = 12;
    }
    class Teacher{
       public:
       Teacher();
       Student * stu;
       void visit();
    }
    // 类外定义构造函数
    Teacher::Teacher(){
       stu = new Student;
    }
    // 类外定义函数
    Teacher::visit(){
    cout<<stu->m_Name()<<endl;
    cout<<stu->m_Age()<<endl;
    }
    void main(){
       Teacher teacher;
       teacher.visit();
    }
    • 成员函数做友元

    #include<iostream>
    #incldue<string>
    using namespace std;
    class Building;
    class GoodGay{
       public:
       GoodGay();
       void visit();
       Building *building;
    }
    GoodGay::GoodGay(){
       building = new Building;
    }
    GoodGay::visit(){
       // 该函数作为Building友元,可以访问私有成员
       cout<<building->m_BedRoom<<endl;
    }
    class Building{
       // 告诉编译器指定类下的指定函数作为当前类友元,可以访问当前类私有成员
       friend void GoodGay::visit();
       public:
       Building();
       string m_SittingRoom;
       private:
       string m_BedRoom;
    }
    Building::Building(){
    m_SittingRoom = "客厅";
       m_BedRoom = "卧室";
    }

    void main(){
       
    }

    运算符重载

    class Person{
       public:
       Person operator+(Person &p){
           a = new int(10);
      }
       int m_Num;
       int* a;
       // 前置操作符重载
       Person& operator++(){
           m_Num++;
           return *this
      }
       // 后置操作符重载,(占位参数表示是后置运算符)
       Person operator++(int){
           Person temp = *this;
           m_Num++;
           return temp;
      }
       
    };
    // 第一个参数是调用的对象
    // 全局重载
    ostream operator<<(ostream &cout,Person p){
       cout<<p.name<<endl;
       return cout;
    }
    // 深拷贝
    Person& operator=(Person &p){
       if(a!=NULL){
    delete a;
          a = NULL;
      }
       a = new int(*(p.a));
       return *this;
    }

    C++支持多继承,但一般不使用;父类中的所有属性都会继承到子类,只是私有成员不可见

    // 公共继承 父类属性全部继承到子类,但私有不可见
    class Son:public Base;
    // 公共继承 父类属性全部继承到子类,公共属性变成保护,但私有不可见
    class Son:protected Base;
    // 公共继承 父类属性全部继承到子类,公共和保护属性变成私有属性,但私有不可见
    class Son:private Base;
    // 访问父类属性
    class Base{
       public:
       int m_A;
       Base(){
           m_A = 10;
      }
       static m_B;
       static void say(){}
    };
    // 类外初始化静态变量
    int Base::m_B = 20
    class Son:public Base{
    };
    int main(){
       Son s;
       Son::Base::m_B;
       Son::Base::say();
       s.Base::m_A;
       return 0;
    }
    // 多继承
    class A:public B,public C;
    // 当多继承的父类出现重复定义属性,必须通过::区分不同域对象属性
    // 利用虚继承,解决父类重复属性;虚基类保存一个
    class A{
       public:
       int a;
    };
    class B:virtual public A{};
    class C:virtual public A{};
    // 此时D两个属性a(从B、C继承)都只是一个指针(vbprt),指向了虚基类表,表中记录了虚基类属性(A中的a属性)偏移量
    class D:public B,public C{};

    多态分为两类

    • 静态多态:函数重载、运算符重载,函数重载;地址早绑定,编译阶段确定

    • 动态多态:父类引用指向子类对象;地址晚绑定,运行阶段确定

      1. 有继承关系

      2. 重写父类虚函数(virtual)

      3. 父类指针或者引用 指向子类对象

    class Animal{
       public:
       // 地址早绑定
       void speak(){
           cout<<"动物在说话"<<endl;
      }
       // 地址晚绑定
       virtual void speak(){
           cout<<"动物在说话"<<endl;
      }
    };
    class Cat:public Animal{
       public:
       void speak(){
           cout<<"猫在说话"<<endl;
      }
    };
    void doSpeak(Animal &animal){
       animal.speak();
    };
    int main(){
       Cat cat;
       // 地址早绑定,编译时就确定会调用父类方法
       doSpeak(cat);
       return 0;
    }

    动态多态原理:虚函数记录一个vfprt(虚函数指针)指针,指向虚函数表,虚函数表中记录函数实现入口地址;子类重写虚函数后覆盖子类的虚函数表中记录的入口地址(父类虚函数指针没变,还是指向以前的虚函数表地址)

    父类中的虚函数可以不实现,直接赋值0就是 纯虚函数。即:virtual 返回值类型 函数名(参数列表)=0;当类中有一个纯虚函数,该类被称为 抽象类;抽象类无法实例化对象,子类如果不实现纯虚函数也会成为 抽象类

    C++高级

    c++中用模板实现泛型编程,分为 函数模板类模板

    函数模板

    函数模板中类型参数不能有默认参数

    普通函数函数模板 重名调用规则:

    1. 如果两者都可以调用,则优先调用普通函数

    2. 通过空参数列表强制调用函数模板,例:int<>(1)

    3. 函数模板可以重载

    4. 如果 函数模板 更匹配则调用 函数模板

    template<typename T>
    void func(T t){
       
    };
    // 提供具体类型实现规则
    template<> void func(Person &p){
       
    };
    // 显示指定类型,可以发生隐式类型转换(向上转型)
    func<int>(1);
    // 自动类型推导,如果使用自动类型推导,则不会发生隐式类型转换(向上转型)
    func(1)

    类模板

    类模板 没有自动类型推导;类模板 在类型参数列表中可以定义默认参数;普通成员函数在创建对象时候就就创建,类模板 中成员函数在调用时创建,动态绑定;类模板 中的类型参数必须在创建对象时指定

    #include<iostream>
    #include<string>
    using namespace std;
    template<class NameType,class AgeType = int>
    class Person{
    public:
       Person(NameType name,AgeType age){
           this->m_Name=name;
           this->m_Age=age;
      }
       // 类内声明,类外实现
       void info();
    private:
       NameType m_Name;
       AgeType m_Age;
    };
    // 类外实现模板函数,即使不使用类型参数也要加上限定
    template<class T1,class T2>
    // 类外实现成员函数必须通过::前面加上类名作为作用域
    void Person<T1,T2>::info(){
       
    }
    int main(){
       Person<string> p("",1)
       return 0;
    }

    类模板 中定义友元函数

    #include <iostream>
    #include <string>
    using namespace std;
    template<class T1,class T2>

    template<class T1,class T2>
    class Person;  
    // 友元函数模板类外实现
    template<class T1,class T2>
    void info2(Person<T1,T2>p){
     
    }
    template<class T1,class T2>
    class Person{
       // 类模板内声明定义友元函数
       friend void info1(Person<T1,T2> p){}
       // 类模板内声明友元函数,类外定义;需要让编译器提前知道有类外实现代码
       // 加<>空参数列表表明是函数模板的类外实现
       friend void info2<>(Person<T1,T2> p);
    };

    仿函数

    类中重载()运算符,将对象像函数一样调用,可以实现闭包;重载()并且返回值是bool类型,则将该类称为谓词

  • 相关阅读:
    LINQ to SQL 运行时动态构建查询条件
    MVC ViewData和ViewBag
    下面介绍一下 Yii2.0 对数据库 查询的一些简单的操作
    php表单中如何获取单选按钮与复选按钮的值
    [moka同学摘录]Yii2.0开发初学者必看
    Yii路径总结
    css样式reset
    ajax onblur 用法
    jquery自定义插件——window的实现
    jQuery使用ajaxStart()和ajaxStop()方法
  • 原文地址:https://www.cnblogs.com/leon618/p/13783396.html
Copyright © 2020-2023  润新知