• 【星海出品】C++的基础(一)理论知识


    数组

    a[]表示访问数组元素,比如int a[10]定义了长度为10的整型数组,标号从0-9,a[3]就表示下标为3的元素(第四个)

    • new运算符创建数组的形式:

    数据类型 数组名 = new 数据类型 [数组长度]。
    float *p = new float [5];

    变量

    在C++ 中,变量的三个基本要素是指:

    变量名、变量类型、变量值。

    静态成员变量

    初始化:
    静态成员变量可以初始化,但只能在类体外进行初始化。如:
    long long student::number = 13926572996; //在类体外对静态成员变量赋值
    其一般形式为:
    数据类型 类名::静态成员变量名 = 初值;

    生存周期分为“静态生存周期”与“动态生存周期”。
    静态生存期的变量有
    (1)全局变量
    (2)静态局部变量
    (3)静态成员变量
    从定义开始直到本程序结束才被销毁
    特点:
    (1)静态成员函数没有this指针,正因为他没有this指针,他才可以不通过对象来对静态成员变量进行访问。
    (2)静态成员函数中,无法对本类的非静态成员进行默认访问

    动态生存周期
    对象或者变量从定义开始,到其所在函数或者语句块结束时被销毁
    例如: i从定义开始,到for循环结束而消失

    重载流插入运算符

    重载类PrintInfo
    (ostream &, const PrintInfo & )

    拷贝构造函数

    使用对象的引用来初始化创建中的对象的函数是 拷贝构造函数 。

    复制构造函数

    复制构造函数使用 对象的引用 作为形式参数。

    常量与非常量

    1. 常量的值不可以修改,任何尝试修改常量的操作都会导致编译错误。而变量可以通过赋值来改变。

    2. 常量定义后就不可修改,所以常量在定义时就必须初始化。变量可以定义时暂时不进行初始化。常量初始化的时候必须直接赋值。

    局部变量没有赋初值时,其值是不确定的。
    全局变量没有赋处置时,默认为0

    预处理

    C++ 提供预处理的语句有三种
    文件包含、条件编译和宏定义

    联编

    静态联编:编译阶段就将函数实现与函数调用关联起来;
    动态联编:在程序执行阶段才将函数实现和调用关联;

    构造析构

    class C:public A,public B
    构造函数执行顺序 A,B,C
    析构函数执行顺序 C,B,A

    构造函数

    构造函数不应该有void

    封装

    “封装” 要求有一个对象应具备明确的功能,并具有接口以便和其他对象相互作用。

    继承

    公有继承为公有
    私有继承为私有

    派生类也是封闭类的情况下,
    生成派生类对象时,根据派生层次从上至下依次执行所有基类的构造函数。

    派生类从基类保护继承时,基类中的私有成员在派生类中是隐藏的,不能直接访问。

    继承性允许派生类继承基类的部分成员,并允许增加新的成员或重定义基类的成员。

    指针、对象

    通过对象访问成员变量的一般格式为 “ 对象名.成员变量名 ”
    指针类型的强制转换格式:(char *)p

    运算符重载

    运算符重载为成员函数时,若参数表中无参数,重载的是一元运算符。
    二元运算符只需要传递一个参数。

    运算符重载格式

    • operator+( & p)
    • ostream& operator<<(ostream& cout, & p)
    • bool operator > ( & p)
    • & operator++()
    • operator++(int)
    • &operator=( & p)

    案例:

    +运算符重载
    class Person {
    public:
    	//成员函数重载+号,本质调用为Person p3 = p1.operator+(p2);
    	Person operator+(Person& p)
    	{
    		Person temp;
    		temp.m_A = this->m_A + p.m_A;
    		temp.m_B = this->m_A + p.m_B;
    		return temp;
    	}
    
    	int m_A;
    	int m_B;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    左移运算符重载
    #include 
    using namespace std;
    
    class Person {
    public:
    	//通常,我们不会利用成员函数重载左移运算符,因为无法将cout在左侧实现,调用时得写成p<
    	int m_A;
    	int m_B;
    };
    
    //利用全局函数重载左移运算符
    ostream& operator<<(ostream& cout, Person& p)
    {
    	cout << "p.m_A= " << p.m_A << endl;
    	cout << "p.m_B= " << p.m_B << endl;
    	return cout;
    }
    
    int main()
    {
    	Person p;
    	p.m_A = 10;
    	p.m_B = 10;
    
    	cout << p << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    模板类重载左移运算符

    #include 
    #include 
    using namespace std;
    
    template <class T1,class T2>
    class Pair
    {
    public:
        T1 key;  //关键字
        T2 value;  //值
        Pair(T1 k,T2 v):key(k),value(v) { };
        bool operator < (const Pair<T1,T2> & p) const;
    	bool operator > (Pair<T1,T2> & p){
    		cout << "key:"<< key << endl;
    		cout << "p.key:" <<p.key << endl;
    		return key > p.key;
    	};
    	
    	friend ostream& operator<<(ostream& cout, Pair<T1,T2>& p)
    	{
    		cout << endl << "p.key = " << p.key << endl;
    		return cout;
    	};
    	
    	Pair operator+(Pair<T1,T2>& p)
    	{
    		Pair<string,int> temp("",0);
    		temp.value = value + p.value;
    		return temp;
    	};
    };
    
    template<class T1,class T2>
    bool Pair<T1,T2>::operator < (const Pair<T1,T2> & p) const
    //Pair的成员函数 operator <
    { //"小"的意思就是关键字小
        return key < p.key;
    }
    
    int main()
    {
        Pair<string,int> student("Tom",20); //实例化出一个类 Pair
        cout << student.key << " " << student.value << endl;
        
        Pair<string,int> student1("Zack",18);
        
    	cout << student1.key << endl;
    	cout << "--"<< endl;
        if(student1 > student) cout << "1";
    	if(student < student1) cout << "2";
    	cout << student << endl;
    	
    	Pair<string,int> student3("sum",0);
    	student3 = student + student1;
    	cout << student3.value << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    重载运算符++
    #include 
    using namespace std;
    
    class MyInteger
    {
    public:
    	MyInteger()
    	{
    		m_Num = 10;
    	}
    	
    	//重载前置++运算符(++i)
    	MyInteger & operator++()
    	{
    		++m_Num;
    		return *this;		//将类本身做返回
    	}
    	
    	//重载后置++运算符(i++)
        //因为函数返回的是局部变量temp,当函数调用完后会释放局部变量,所以函数只能返回值,而不是引用&
    	MyInteger operator++(int)	//int 代表占位参数,用于区分前置和后置递增
    	{
    		MyInteger temp = *this;
    		m_Num++;
    		return temp;		//将类本身做返回
    	}
    
    	int m_Num;
    };
    
    ostream &operator<<(ostream &cout, MyInteger &myint)
    {
    	cout << myint.m_Num;
    	return cout;
    }
    
    int main()
    {
    	MyInteger myint;
    	cout << ++myint << endl;
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    (1).重载前置运算符不需要传入参数,而重载后置运算符需要传入一个占位参数int;

    (2).重载前置运算符返回的是引用,后续可以对该值继续链式调用; 重载后置运算符直接返回局部变量的值,因为局部变量在函数调用完后就被释放,所以如果引用一个局部变量地址就会报错。

    赋值运算符重载
    #include 
    using namespace std;
    
    class Person {
    public:
    	int *m_Age;
    
    	Person(int age)	
    	{
    		m_Age = new int(age);
    	}
    
    	~Person()		//写出析构函数是为了方便看出浅拷贝和深拷贝的区别
    	{
    		if (m_Age) {
    			delete m_Age;
    			m_Age = NULL;
    		}
    	}
    
    	Person &operator=(Person& p)
    	{
    		//先判断是否有属性在堆区,如果有先释放干净,然后再深拷贝
    		if (m_Age)
    		{
    			delete m_Age;
    			m_Age = NULL;
    		}
    		//深拷贝
    		m_Age = new int(* p.m_Age);
    		
    		//编译器只提供如下浅拷贝:
    		//m_Age = p.m_Age;
    
    		return *this;
    	}
    };
    
    void test()
    {
    	Person p1(10);
    	Person p2(20);
    
    	p2 = p1;		//赋值操作,调用重载函数
    
    	cout << "p1.m_Age= " << *p1.m_Age << endl;
    	cout << "p2.m_Age= " << *p2.m_Age << endl;
    }
    
    int main()
    {
    	test();
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    bool运算符重载
    bool operator==(Person& p)
    {}
    
    • 1
    • 2
    bool operator < (const Pair<T1,T2> & p) const;
    
    类外定义
    template<class T1,class T2>
    bool Pair<T1,T2>::operator < (const Pair<T1,T2> & p) const
    //Pair的成员函数 operator <
    { //"小"的意思就是关键字小
        return key < p.key;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    函数调用运算符()重载
    #include 
    using namespace std;
    
    class MyPrint
    {
    public:
    	void operator()(string str)
    	{
    		cout << str << endl;
    	}
    };
    
    int main()
    {
    	MyPrint myprint;
    
    	myprint("hello world!");		//这里的()使用了重载函数,其本身也像一个函数
    
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    抽象类,类模板、模板类

    Class *p
    抽象类定义:如果一个类中至少有一个纯虚函数,那么这个类就被称为抽象类。
    派生类中必须重载基类中的纯虚函数,否则它仍然是一个抽象类。
    从基类继承类的纯虚函数,在派生类中仍然是虚函数
    抽象类的一个重要特点:抽象类只能用作派生类的基类,而不能直接创建对象实例。
    原因:其中一个或多个函数没有定义,但仍可使用指向抽象类的指针支持运行时多态性。

     类模板的重点是模板。表示的是一个模板,专门用于产生类的模子。例子:  
    
    • 1

    类模板
    类模板中的成员函数全部都是模板函数。
    加参数型:

    template<class NameType,class AgeType=int>
    class Teacher
    {
        Teacher(NameType name,AgeType age){
            this->m_Name = name;
            this ->m_Age = age;    
        }
        NameType m_Name;
        AgeType m_Age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    使用类模板创建对象时,要随类模板名给出对应于类型形参或普通形参的具体实参,可以使用格式

    • “类模板名 <模板参数表> 对象名”

    模板类

    Teacher<string, int> t2("xiansifan", 22);
    //或者
    Teacher<string> t1("xiansifan", 234);
    //类模板在模板参数列表中可以有默认参数
    
    • 1
    • 2
    • 3
    • 4

    深拷贝,手动定义 Rect 类中的拷贝函数,默认定义的 Rect 类为浅拷贝。

    Rect(const Rect& r)  
    {  
        width = r.width;  
        height = r.height;  
        p = new int;    // 为新对象重新动态分配空间  
        *p = *(r.p);  
    }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    函数头include

    iomanip

    setbase(n)

    • 设置整数为n进制(n=8,10,16)

    setfill(n)

    • 设置字符填充,c可以是字符常或字符变量

    setprecision(n)

    • 设置浮点数的有效数字为n位

    setw(n)

    • 设置字段宽度为n位

    setiosflags(ios::fixed)

    • 设置浮点数以固定的小数位数显示

    setiosflags(ios::scientific)

    • 设置浮点数以科学计数法表示

    setiosflags(ios::left)

    • 输出左对齐

    setiosflags(ios::right)

    • 输出右对齐

    setiosflags(ios::skipws)

    • 忽略前导空格

    友元函数

    友元运算符@obj 被 C++ 编译器解释为
    operator@(obj)

    friend void Student::score();
    
    • 1

    虚函数

    在基类的实现纯虚函数的方法是在函数原型后添加=0
    (virtual void funtion1()=0)

    一般的讲,如果类中定义有虚函数,则其析构函数也应该声明为虚函数,特别是在析构函数中需要完成一些有意义的操作,比如释放内存时

    当编译系统编译含有虚函数的类时,将为它建立一个虚函数表,表中的每一个元素都指向一个虚函数的地址。

    函数模板和模板函数

    ASCII码

    put输出ASCII转字符
    例如char c = ‘a’
    cout put(c+25)

    结果:z

    面向对象程序设计

    面向对象程序设计能进行功能抽象
    面向对象程序设计能进行数据抽象

    c++对文件的使用方式

    头文件,创建对象,打开文件,对数据操作,关闭文件

    文件类型分为两种:

    文本文件:文本文件的ASCII码形式存储在计算机中
    二进制文件:文本文件的 二进制 形式存储在计算机中,用户一般不能直接读懂它们

    操作文件的三大类:

    ofstream:写操作
    ifstream:读操作
    fstream:读写操作

    包含头文件

    #include
    ofstream是从内存到硬盘,ifstream是从硬盘到内存,其实所谓的流缓冲就是内存空间;
    fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式(in)打开文件,而ofstream默认以输出方式(out)打开文件。

    创建流

    ofstream ofs; //写文件
    ifstream ifs; //读文件

    打开文件

    ofs.open(“文件路径”,打开方式);

    读写数据

    ofs<<“写入的数据”;
    ifs<<变量名/字符串; //读数据

    关闭文件

    ofs.close();

    文件打开方式:

    ios::in : 为读文件而打开文件
    ios::out : 为写文件而打开文件
    ios::app : 初始位置:文件尾
    ios::app : 追加方式写文件
    ios::trunc : 如果文件存在先删除,在创建
    ios::binary : 二进制方式
    注意,文件打开方式可以配合使用,利用 | 操作符
    例如:用二进制方式写文件 ios::out | ios::binary

    std::fstream ofs(“F:\1.txt”, std::ios::in | std::ios::out);

    写文件

    #include
    #include
    using namespace std;
    #include    //头文件包含
     
    //文本文件 - 写文件
     
    void text01()
    {
        //1.包含头文件 fstream
     
        //2.创建流对象
        ofstream ofs;        // o - 写 f - 文件 stream - 流
     
        //3.指定打开方式
        ofs.open("text.txt", ios::out);
     
        //4.写内容
        ofs << " 姓名:张三" << endl;
        ofs << " 年龄:19 " << endl;
        ofs << " 性别:男 " << endl;
     
        //5.关闭文件
        ofs.close();
     
    }
    int main()
    {
        text01();
        return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    读文件

    void text02()
    {
        //1.包含头文件 fstream
     
        //2.创建流对象
        ifstream ifs;            //ifstream ifs("Person.txt", ios::out | ios::binary);
     
        //3.打开文件 并且判断是否打开成功
        ifs.open("text.txt", ios::in | ios::binary);
        if (!ifs.is_open())
        {
            cout << "文件打开失败" << endl;
            return;
        }
     
        //4.读内容
     	for (int i = 0; i < 5 ; i++ ){
    	
     		char str[100] = { 0 };
     		ifs.getline(str, 100);
     		std::cout << str << std::endl;
     	}
    
        //5.关闭文件
        ifs.close();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    判断文件行数

    #include 
    
    int main()
    {
        FILE * fp = NULL; //文件指针。
        int c, lc=0; //c为文件当前字符,lc为上一个字符,供结尾判断用。
        int line = 0; //行数统计
        fp = fopen("text.txt", "r");//以只读方式打开文件。
        if(fp == NULL) return -1; // 文件打开失败。
        while((c = fgetc(fp)) != EOF) //逐个读入字符直到文件结尾
        {
            if(c == '\n') line ++; //统计行数。
            lc = c; //保存上一字符。
        }
        fclose(fp); //关闭文件
        if(lc != '\n') line ++;//处理末行
         
        printf("文件共有%d行。\n", line);
         
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
  • 相关阅读:
    mac拷贝文件到u盘,mac拷贝文件到u盘很慢
    R语言使用append函数在向量数据中的指定位置插入新的元素(一个或者多个数值)
    人工神经网络数学模型图,神经网络模型数学建模
    UI组件库Kendo UI for Vue原生组件中文教程 - 如何开始制作动画
    【C语言】解决 “address of stack memory associated with local variable ‘num‘ returned”
    基本程序单元Activity
    网络复习题带答案
    基于瞬时无功功率ip-iq的谐波信号检测Simulink仿真
    通关GO语言22 网络编程:Go 语言如何通过 RPC 实现跨平台服务?
    经典面试题-小于N的最大数
  • 原文地址:https://blog.csdn.net/weixin_41997073/article/details/126856692