• C++ 类


    类的基本思想时数据抽象和封装,数据是一种依赖接口和实现所能执行的操作,封装类的接口和实现分离。隐藏了实现细节,类的用户只能使用接口但无法访问具体实现。
    创建类时,使用#ifndef可以防止多次包含同一个文件。

    一,类的基础

    类的设计尽可能将共有接口与实现细节分开。类的声明类似结构声明,可以包括数据成员和函数成员,声明有是由部分,私有部分只能禅院函数进行访问,共有部分可以使用类的对象程序直接访问。

    1,类的声明结构

    class  类名{
        private:
            私有数据成员和成员函数声明
        public:
            公有数据成员和成员函数的声明
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    类的实现建议与声明同名,直接定义在类的声明中的函数是内联函数。
    例如:

    #ifndef STOCK_H
    #define STOCK_H
    #include<string>
    //类的声明
    class Stock{
    private:
        long shares;
        double share_val;
        double total_val;
        void set_tot();
    public:
        //声明成员函数
        void acquire(const long n,double pr);
        void buy(long num,double price);
        void sell(long num,double price);
        void update(double price);
        void show();
    };
    #endif // STOCK_H
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    共有部分的内存构成了设计的抽象部分,将数据封装到私有部分可以保护数据的完整性。

    2,类的定义

    Stock::Stock(const string & company,long shares,double share_val){
    }
    
    • 1
    • 2

    使用时

    Stock food = Stock("Word Cabbage",250,1.25);
    或
    Stock garment("Furry Mason",50,2.5);
    
    • 1
    • 2
    • 3

    类的定义就是对象,使用时必须添加类的头文件。
    公有成员可以被所有函数访问,私有成员只能被自己的成员函数访问。

    3,构造函数

    未提供显示初始值时,用来创建对象的构造函数,默认构造函数没有参数。
    当程序创建未显示初始化的类对象时,会调用默认构造函数。
    例如:

    struct Sales_data
    {
        Sales_data() = default;//默认构造函数
        Sales_data(const string& s) :bookNo(s) {};//构造函数
        Sales_data(const string& s, unsigned n, double p):bookNo(s),units_sold(n),revenue(p*n) {}//多参构造函数
        Sales_data(std::istream&);//构造函数
    
        string isbn() const { return bookNo; }
        Sales_data& combine(const Sales_data&);
        double avg_price() const;
        string bookNo;
        unsigned units_sold = 0;
        double revenue = 0.0;
    };
    
    int main() {
        Sales_data total;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4,析构函数

    用构造函数创建对象后,程序复杂更新该对象,知道其过期时会自动调用析构函数,析构函数主要用来完成清理工作。
    析构函数是在函数名之前新增一个“~”符号

    Stock::~Stock(){
        
    }
    
    • 1
    • 2
    • 3

    5、this指针

    代指当前类的对象,指向当前调用函数的对象

    const  Simple  &Simple::top(const  Simple&a )const{
        …
        return  *this
    }
    
    • 1
    • 2
    • 3
    • 4

    *this 表示当前对象

    6、运算符重载

    使对象能用运算符操作
    例如a1=a2+a3;
    限制
    1)不是所有的运算符都能重载
    2)重载不能改变运算符的优先级和结合性
    3)重载不能改变运算符的操作数个数
    4)不能创建新的运算符
    重载赋值运算符,函数名为operator =l
    例如

    A operator +(const  A&a )const
    
    • 1

    7、友元

    永许访问私有成员,在类声明中用friend创建友元,友元的声明可以在类的声明任意地方,通常放在最后或最前面,主要用于运算符重载

    class{
        friend  int  fun(double);
    }
    
    • 1
    • 2
    • 3

    如果对象是通过new创建的,则它将驻留在栈内存和自由内存区域中,当使用delete释放内存时,其析构函数将自动被调用。
    每个类只有一个析构函数,析构函数没有返回类型,有没有参数。

    二,类的访问与封装

    1,访问修饰符

    在C++中也有对应的访问权限修饰符
    1)public:成员在整个程序内可被访问
    2)private:成员可以被类的成员函数访问,但不能被使用该类的代码访问,private部分封装了类的实现细节。
    2)protected:子类可访问
    例如:

    class Student{
    
    private:
      int age;
    public:
       setAge(int age);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    使用访问修饰符时个数限制,只要根据要求放到需要的访问区间内就可以正常使用。
    使用class和struct关键字的区别,struct的成员默认是public访问区间的,class默认是private类型的。

    2,可变的数据成员

    为类的成员添加mutable修饰后,便可以在const成员函数内修改类的数据成员。
    例如:

    class Student{
        private:
        int height;
        public:
         void changeProperty()const	;
    }
    void Student::changeProperty()const
    {
    	height = 30;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    在类中声明了一个const的成员函数,然后再定义中修改类的属性时,编译器会直接报错,如果把height使用mutable进行修饰,则可以进行修改。

    三,构造函数

    在C++中对象的使用,是先定义,在赋值
    例如:

    string foo = "Hello World!";//定义并初始化
    string bar;                            //默认初始化成空string对象
    bar = "Hello World!";         //为bar赋一个新值
    
    • 1
    • 2
    • 3

    1,构造函数的参数
    在构造函数中如果成员是const或者应用的话,必须将其初始化。
    例:

    class ConstRef
    {
    public:
    	ConstRef(int ii) :i(ii), ci(ii), ri(i) {};
    private:
    	int i;
    	const int ci;
    	int& ri;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    如果成员是const,引用,或者属于某种未提供默认构造函数的类类型,我们
    必须通过构造函数初始值列表为这些成员提供初值。

    2,默认实参和构造函数
    在构造函数中可以提供默认的实参
    例如:

    class Student{
    
    public:
       Student(int num = 20):age(num){}
    private:
    int age;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    注:如果成员属性的初始化赋值有互相依赖,则在构造函数中必须按照一定的顺序进行初始化赋值。

    3,委托构造函数
    使用所属类的其他构造函数执行自身初始化的过程。
    例如:

    class Student
    {
    public:
    
    	Student(int l1, int l2, int l3) :age(l1), height(l2), weight(l3) {}
    	Student(int l1, int l2) :Student(l1, l2, 0) {}
    	Student(int l1) :Student(l1, 0, 0) {}
    	~Student();
    
    private:
    	int age;
    	int height;
    	int weight;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    四,类的静态成员

    把类的成员声明成静态成员后,它就会变成只和类有关联,和类的每个对象无关联。

    1,静态成员的声明

    在成员的声明之前添加static进行修饰,类的静态成员存在于任何对象之外,对象中不能包含任何于静态成员有关的数据。
    例如:

    #include<istream>
    
    using namespace std;
    class Account
    {
    public:
    	void calculate() { amount += amount * interestRate; }
    	static double rate() { return interestRate; }
    	static void rate(double);
    
    private:
    	std::string owner;
    	double amount;
    	static double interestRate;
    	static double initRate();
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    静态成员函数也不与任何对象绑定在一起,他们不包含this指针。
    使用静态成员函数时,直接使用“类名::成员函数”的方式进行调用。

    2,定义静态成员

    在静态成员定义时,其static关键字只能在头文件中进行声明,在定义时不能重复static关键字
    例如:

    void Account::rate(double newRate){
        interestRate = newRate;
    }
    
    • 1
    • 2
    • 3

    静态成员不能在类的内部初始化,只能在类的外部定义和初始化每一个静态成员。静态成员一旦被定义,将一直存在于程序的整个生命周期中。

    3,静态成员的类内初始化

    可以为静态成员提供const整型类型的类内初始化,但需要静态成员必须是字面值常量类型的constexpr,初始值必须是常量表达式。
    因为这些成员本身就是常量表达式,所以他们能用在所有适合于常量表达式的地方。
    例如:

    class Account
    {
    public:
    	void calculate() { amount += amount * interestRate; }
    	static double rate() { return interestRate; }
    	static void rate(double);
    
    private:
    	std::string owner;
    	double amount;
    	static constexpr int period = 30;//是一个常量表达式
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    注:
    静态成员可以是它所属的类类型,而非静态数据成员则受到限制,只能声明成它所属类的指针和引用。

    class Account{
    private:
         static Account mm1;//静态成员可以是不完全类型
         Account* pr;
         Account mm;//编译器报错,数据成员必须是完全类型。
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    静态成员可以作为默认的实参,而普通成员则不可以。

    五,类的继承

    在一个或多个已有类的基础上扩展属性和方法,形成一个强大的类。
    基类:已有的类
    派生类:扩展后的类
    这样可以实现代码重用,也可以重用不公开的类
    继承分为三种
    1)公有继承,public修饰
    2)私有继承,private 修饰
    3)保护继承,procted修饰

    1、重定义基类函数

    重新定义实现基类的函数,添加自己扩展的实现。最后要添加基类的调用。

    2、公有继承与多态

    在基类中添加虚函数,当基类指针指向派生类对象,并对指针调用虚函数时,会到派生类中去寻找同原型的函数并执行,如果不存在,则调用基类的函数。

    3、protected 保护的成员

    只能被自己的派生类访问,可以提高派生类的效率。

    4、多继承

    一个类继承多个类,会出现二义性问题
    解决方法
    1)使用作用域运算符
    2)重新封装调用基类
    3)使用虚基类
    例如:

    class Parent{
    private:
    int age;
    public:
    int getAge();
    }
    
    class Child:Parent{
    	public:
    	private:
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
  • 相关阅读:
    Spark Executor decommission 原理分析
    一篇学通Axios
    openEuler 22.03 LTS 安装 Docker CE 和 Dcoker Compose
    WMI使用学习笔记
    【JavaEE】网络编程
    初识深度学习
    Redis 主从架构数据同步
    项目前的知识回顾
    educoder_python:4-1-逻辑控制(if)第2关:求解一元二次方程组
    MySQL SQL优化
  • 原文地址:https://blog.csdn.net/zdc9023/article/details/126368760