笨蛋学C++【C++基础第六弹】

ops/2024/10/20 18:58:16/

C++基础第六弹

  • C++面向对象
    • 1.C++类 & 对象
      • 1.1C++类定义
      • 1.2C++对象
      • 1.3访问数据成员
      • 1.4类成员函数
      • 1.5类访问修饰符
        • 公有public成员
        • 私有private成员
        • 受保护protected成员
        • 继承中的特点
      • 1.6构造函数 & 析构函数
        • 类的构造函数
        • 带参数的构造函数
        • 使用初始化列表来初始化字段
        • 类的析构函数
      • 1.7拷贝构造函数
      • 1.8友元函数
      • 1.9内联函数
      • 1.10C++中的this指针
      • 1.11C++指向类的指针
        • 声明和初始指向类的指针
        • 动态分配内存
        • 指向类的指针作为函数参数
      • 1.12C++类的静态成员
        • 静态成员函数

C++面向对象

1.C++类 & 对象

  • 类是C++的核心特性,通常被称为用户定义的类型
  • 类用于指定对象的形式,是一种用户自定义的数据类型,是一种封装了数据和函数的组合
    • 类中的数据称为成员变量
    • 类中的函数称为成员函数
  • 类可以被看作是一种模板,用来创建具有相同属性和行为的多个对象

1.1C++类定义

  • 定义类需要用到关键字 class,然后指定类的名称,类的主体是包含在一对花括号中,主体包含类的成员变量和成员函数

  • 语法:

    class 类名{访问修饰符(public/protected/private):成员变量;成员函数();
    }
    

1.2C++对象

  • 对象是根据类来创建的,声明类的对象,就像声明基本类型的变量一样

1.3访问数据成员

  • 类的对象的公共数据成员可以使用直接成员访问运算符 .来访问

    //
    // Created by 16690 on 2024/4/21.
    //
    #include <iostream>using namespace std;class Box {
    public://成员变量声明double length;double breadth;double height;//成员函数声明double get(void);void set(double len, double bre, double hei);
    };//成员函数定义
    //get函数
    double Box::get(void) {return length * breadth * height;
    }//set函数
    void Box::set(double len, double bre, double hei) {length = len;breadth = bre;height = hei;
    }int main(void) {Box box1;Box box2;Box box3;double volume = 0.0;//box1信息box1.height = 5.0;box1.length = 6.0;box1.breadth = 7.0;//box2信息box2.height = 10.0;box2.length = 12.0;box2.breadth = 13.0;//box1体积volume = box1.height * box1.length * box1.breadth;cout << "box1体积:" << volume << endl;//box2体积volume = box2.height * box2.length * box2.breadth;cout << "box2体积:" << volume << endl;box3.set(16.0, 18.0, 20.0);volume = box3.get();cout << "box3体积:" << volume << endl;return 0;
    }
    

1.4类成员函数

  • 类的成员函数是指哪些把定义和原型写在类定义内部的函数,就像类定义中的其它变量一样

  • 类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员

  • 成员函数可以定义在类定义内部,或**单独使用范围解析运算符 ::**来定义,在类定义中定义的成员函数把函数声明为内联,即便没有inline标识符

  • 使用范围解析运算符 ::,也叫作用域区分符,指明一个函数属于哪个类或一个数据属于哪一个类。 :: 运算符之前必须使用类名,调用成员函数是在对象上使用点运算符 .

    Box box;
    box.get();
    ------------------------------------------------------------
    Box::get(){}
    
    • 未使用类成员函数

      class Box {
      public://成员变量声明double length;double breadth;double height;//成员函数声明double get(void);void set(double len, double bre, double hei);
      };//成员函数定义
      //get函数
      double Box::get(void) {return length * breadth * height;
      }//set函数
      void Box::set(double len, double bre, double hei) {length = len;breadth = bre;height = hei;
      }
    • 使用类成员函数

      class Boxs{//成员变量声明double length;double breadth;double height;//成员函数声明//使用inline标识符inline double get(void){return length * breadth * height;}//默认内联标识符void set(double len, double bre, double hei){length = len;breadth = bre;height = hei;}
      };
      

1.5类访问修饰符

  • 类成员的访问限制是通过在类主体内部对各个区域标记 public、protected、private来指定的,

  • 一个类可以有多个public、protected、private标记区域,每个标记区域在下一个标记区域开始之前或在遇到类主体结束右括号之前都是有效的

  • 成员和类的默认访问修饰符是private

    class Base{
    public ://公有成员
    protected://受保护成员
    private://私有成员
    };
    
公有public成员
  • 公有成员在程序中类的外部是可访问的,可以不适用任何成员函数来设置和获取公有变量的值
//
// Created by 16690 on 2024/4/21.
//
#include <iostream>
using namespace std;class Base{
public ://公有成员double length;void setLength(double len);double getLength(void);
};void Base::setLength(double len){length = len;
}double Base::getLength(void ) {return length;
}
int main(void){//测试公有成员Base base;//设置长度base.setLength(10.0);cout << "测试公有成员变量:base.getLength() = " << base.getLength() << endl;//因为是公有的,所以可以直接设置长度base.length = 20.0;cout << "测试公有成员变量:base.length = " << base.length << endl;return 0;
}
私有private成员
  • 私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员
  • 默认情况下,类的所有成员都是私有的
  • 一般情况下,在私有区域定义数据,公有区域定义相关的函数
//
// Created by 16690 on 2024/4/21.
//#include <iostream>
using namespace std;class Base{//默认私有成员double width;
public:inline void setWidth(double wid){width = wid;}inline double getWidth(void){return width;}
};int main(void){Base base;//不使用成员函数设置长度// base.width = 10;base.setWidth(10);cout << "length of base:" << base.getWidth() << endl;return 0;
}
受保护protected成员
  • protectd成员变量或函数与私有成员十分类似,但有一点不同,protected成员在派生类(子类)中是可以访问的
//
// Created by 16690 on 2024/4/21.
//
#include <iostream>using namespace std;class Base {
protected:double height;
};class SunBase:Base{
public :void setSunHeight(double hei);double getSunHeight();
};void SunBase::setSunHeight(double hei) {height = hei;
}
double SunBase::getSunHeight() {return height;
}int main(void) {SunBase sun;sun.setSunHeight(10.0);cout << "Sun height is " << sun.getSunHeight() << endl;return 0;
}
继承中的特点
  • public继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:public、protected、privated
  • procted继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:protected、protected、privated
  • private继承:基类public成员,protected成员,private成员的访问属性在派生类中分别变成:private、private、private

  • private成员只有本类成员(类内)和友元访问,不能被派生访问
  • protected成员可以被派生类访问
//
// Created by 16690 on 2024/4/21.
//
#include <iostream>using namespace std;class A {
public:int a;A() {a1 = 1;a2 = 2;a3 = 3;a = 4;}void fun() {cout << a << endl;cout << a1 << endl;cout << a2 << endl;cout << a3 << endl;}public:int a1;
protected:int a2;
private:int a3;};class B : public A {
public:int a;B(int i) {A();a = i;}void fun() {cout << "打印b中的fun=" << a << endl;cout << "打印b中的fun=" << a1 << endl;cout << "打印b中的fun=" << a2 << endl;// cout << a3 << endl; 报错,因为private成员不能够派生类访问}
};int main(void) {B b(10);cout << b.a << endl;cout << b.a1 << endl;b.fun();// cout << b.a2 << endl; //除了父类及子类能够在本类中访问protected成员// cout << b.a3 << endl; //private 成员不允许在外部直接访问return 0;
}
类访问修饰符基/子类的public成员基/子类的protected成员基/子类的private成员
publicpublic成员可见protected成员可见不可见
protectedprotected成员可见protected成员可见不可见
privateprivate成员可见private成员可见不可见

1.6构造函数 & 析构函数

类的构造函数
  • 类的构造函数是类的一种特殊的成员函数,会在每次创建类的新对象时执行
  • 构造函数的名称与类的名称完全相同,且不会返回任何类型,也不会返回void
  • 构造函数可用于为某些成员变量设置初始值
//
// Created by 16690 on 2024/4/21.
//
#include <iostream>
using namespace std;class Line{
public:void setLength(double len);double getLength(void);//构造函数Line();
private:double length;
};
//填写构造函数内容
Line::Line(void){cout << "Object is being created" << endl;
}void Line::setLength(double len) {length = len;
}double Line::getLength() {return length;
}int main(void){Line line;//设置长度line.setLength(6.0);cout << "Length of line : " << line.getLength() << endl;return 0;
}
带参数的构造函数
  • 默认的构造函数是没有任何参数,若需要,构造函数也可以带有参数,这样在创建对象时就会给对象赋初值
//
// Created by 16690 on 2024/4/21.
//
#include <iostream>
using namespace std;class Line{
public:void setLength(double len);double getLength(void);void setWidth(double wid){width = wid;}double getWidth(void){return width;}//构造函数Line(void);Line(double wid);
private:double length;double width;
};
//无参构造函数内容
Line::Line(void){cout << "Object is being created" << endl;
}
//有参构造函数内容
Line::Line(double wid){cout << "Object is being created" << endl;width = wid;
}void Line::setLength(double len) {length = len;
}double Line::getLength() {return length;
}int main(void){Line line;//设置长度line.setLength(6.0);cout << "Length of line : " << line.getLength() << endl;//设置宽度Line lineWid(2.0);cout << "Width of line : " << lineWid.getWidth() << endl;return 0;
}
使用初始化列表来初始化字段
//
// Created by 16690 on 2024/4/21.
//
#include<iostream>using namespace std;
class Line{
public:void setLength(double len);double getLength(void);//构造函数Line() : length(0), width(0) {cout << "Default constructor called" << endl;}Line(double len) : length(len), width(0) {cout << "Single-parameter constructor called, length = " << length << endl;}Line(double wid, double len) : width(wid), length(len) {cout << "Two-parameter constructor called, length = " << length << ", width = " << width << endl;}
private:double length;double width;
};void Line::setLength(double len) {length = len;
}double Line::getLength() {return length;
}
int main(void) {Line line1;Line line2(10.0);Line line3(10.0, 20.0);// 设置长度line1.setLength(5.0);cout << "Length of line1 : " << line1.getLength() << endl;return 0;
}
//
// Created by 16690 on 2024/4/21.
//
#include<iostream>using namespace std;
class Line{
public://构造函数Line(void);Line(double len);Line(double len, double wid);void setLength(double len);double getLength(void);private:double length;double width;
};
Line::Line(void) : length(0),width(0){cout << "Default constructor called" << endl;
}
Line::Line(double len):length(len),width(0) {cout << "Single-parameter constructor called, length = " << length << endl;
}
Line::Line(double len, double wid):length(len),width(wid) {cout << "Two-parameter constructor called, length = " << length << ", width = " << width << endl;
}void Line::setLength(double len) {length = len;
}double Line::getLength() {return length;
}
int main(void) {Line line1;Line line2(10.0);Line line3(10.0, 20.0);// 设置长度line1.setLength(5.0);cout << "Length of line1 : " << line1.getLength() << endl;return 0;
}
类的析构函数
  • 类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行

  • 析构函数的名称与类的名称是完全相同的,就只在前面加了个波浪号(~)作为前缀,不会返回任何值,也不能带有任何参数

    //
    // Created by 16690 on 2024/4/21.
    //
    #include <iostream>
    using namespace std;class Line{public:void setLength(double len);double getLength(void);//构造函数声明Line();//析构函数声明~Line();
    private:double length;
    };Line::Line(void) {cout << "Object is being created" << endl;
    }Line::~Line(void) {cout << "Object is being deleted" << endl;
    }void Line::setLength(double len) {length = len;
    }
    double Line::getLength(void) {return length;
    }
    int main(void){Line line;//设置长度line.setLength(6.0);cout << "Length of line : " << line.getLength() << endl;return 0;
    }
    

1.7拷贝构造函数

  • 拷贝构造函数是一种特殊的构造函数,在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象
  • 拷贝构造函数通常用于
    • 通过使用另一个同类型的对象来初始化新创建的对象
    • 复制对象把它作为参数传递给函数
    • 复制对象,并从函数返回这个对象

  • 若在类中没有定义拷贝构造函数,编译器会自行定义一个,若类带有指针变量,并有动态内存分配,则必须有一个拷贝构造函数

  • 默认的拷贝构造函数实现的只能是浅拷贝,即直接将原对象的数据成员值依次复制给新对象中对应的数据成员,并没有为新对象另外分配内存资源。

  • 当类的数据成员中有指针类型时,我们就必须定义一个特定的拷贝构造函数,该拷贝构造函数不仅可以实现原对象和新对象之间数据成员的拷贝,而且可以为新的对象分配单独的内存资源

  • 语法:

    类名 (const 类名 &obj){//构造函数的主体
    }
    
    //
    // Created by 16690 on 2024/4/21.
    //
    #include <iostream>using namespace std;class Line{
    public:int getLength(void);//简单构造函数Line(int len);//拷贝构造函数Line(const Line &obj);//析构函数~Line();
    private:int *ptr;
    };Line::Line(int len){cout << "调用构造函数" << endl;//为指针分配内存ptr = new int;*ptr = len;cout << "构造函数:" <<ptr << endl;
    }Line::Line(const Line &obj) {cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;ptr = new int;*ptr = *obj.ptr;cout << "拷贝构造函数:" <<ptr << endl;
    }Line::~Line() {cout << "释放内存" << endl;delete ptr;
    }
    int Line::getLength( void )
    {return *ptr;
    }
    void display(Line obj){cout << "line length: " << obj.getLength() << endl;
    }
    int main(void){Line line(10);display(line);return 0;
    }
    

1.8友元函数

  • 类的友元函数是定义在类外部,但有权访问类的私有(private)成员和保护(protected)成员,尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数

  • 友元可以是一个函数,该函数被称为友元函数

  • 友元可以是一个类,该类被称为友元类

  • 若要声明函数为一个类的友元,需要在类定义中在该函数原型前使用关键字friend

    //友元函数
    friend 返回类型 函数名();//声明某个类的所有成员作为另一个类的友元
    friend class 类名;
    

    • 若要访问非static成员时,需要对象做参数
    • 若要访问static成员或全局变量时,则不需要对象做参数
    • 若要做参数的对象是全局对象,则不需要对象做参数
    • 直接调用友元函数,不需要通过对象指针

    //
    // Created by 16690 on 2024/4/22.
    //
    #include <iostream>using namespace std;class Box{double width;
    public:friend void printWidth(Box box);friend class Boxs;void setWidth(double wid);
    };
    class Boxs{
    public:void Print(int width,Box &box){box.setWidth(width);//因为Boxs是Box的友元,可以访问Box的私有成员cout << "Width of box : " << box.width << endl;}
    };
    void Box::setWidth(double wid) {width = wid;
    }void printWidth(Box box){// printWidth是Box的友元,可以直接访问该类的任何成员cout << "Width of box : " << box.width << endl;
    }int main(void){Box box;//使用成员函数设置宽度box.setWidth(10.0);//使用友元函数打印宽度printWidth(box);return 0;
    }
    

1.9内联函数

  • 通常与类一起使用,若一个函数是内联的,那么在编译时,编译器会将函数的代码副本放置在每个调用该函数的地方

  • 对内联函数进行任何修改,都需要重新编译函数的所有客户端,因为编译器需要重新更换一次所有的代码,否则将会继续使用旧的函数

  • 内联函数需要在函数名前面放置关键字 inline,在调用函数之前需要对函数进行定义。

    如果已定义的函数多于一行,编译器会忽略 inline 限定符。

  • 在类定义中的定义的函数都是内联函数,即使没有使用 inline 说明符

    //
    // Created by 16690 on 2024/4/22.
    //#include <iostream>using namespace std;inline int Max(int x, int y) {return (x > y) ? x : y;
    }int main(void) {cout << "Max(10, 5) = " << Max(10, 5) << endl;cout << "Max(20, 15) = " << Max(20, 15) << endl;cout << "Max(0, -10) = " << Max(0, -10) << endl;return 0;
    }

1.10C++中的this指针

  • 在C++中,this指针是一个特殊的指针,它指向当前对象的实例
  • 每个对象都能通过this指针来访问自己的地址
  • this是一个隐藏的指针,可以在类的成员函数中使用,可以用来指向调用对象
  • 当一个对象的成员函数被调用时,编译器会隐式地传递该对象的地址作为this指针
  • 友元函数没有this指针,因为友元不是类的成员,只有成员函数才有this指针
  • 需要用 this -> 成员变量/函数
//
// Created by 16690 on 2024/4/22.
//#include <iostream>using namespace std;class A {
private :int value;
public:void setValue(int value) {this->value = value;}int getValue() {return value;}void print() {cout << "value = " << this->value << endl;}
};int main(void) {A a;a.setValue(10);cout << "gatValue = " << a.getValue() << endl;a.print();return 0;
}

1.11C++指向类的指针

  • 指向C++类的指针与指向结构的指针类似,访问之相类的指针的成员,需要使用成员访问运算符 ->
  • 指向类的指针指向一个类的对象,指向类的指针可以用于访问对象的成员变量和成员函数
声明和初始指向类的指针
//
// Created by 16690 on 2024/4/22.
//
#include <iostream>using namespace std;class MyClass {
public:int data;void display() {cout << "data = " << data << endl;}
};int main(void) {//创建类对象MyClass obj;obj.data = 42;//声明和初始化指向类的指针MyClass *ptr = &obj;//通过指针访问成员变量cout << "通过指针访问成员变量:" << ptr->data << endl;//通过指针调用成员函数ptr->display();return 0;
}
动态分配内存
//
// Created by 16690 on 2024/4/22.
//
#include <iostream>using namespace std;class MyClass {
public:int data;void display() {cout << "data = " << data << endl;}
};int main(void) {//动态分配内存创建类对象MyClass *ptr= new MyClass();ptr->data = 10;//通过指针访问成员变量cout << "通过指针访问成员变量:" << ptr->data << endl;//通过指针调用成员函数ptr->display();//释放内存delete ptr;return 0;
}
指向类的指针作为函数参数
//
// Created by 16690 on 2024/4/22.
//
#include <iostream>using namespace std;class MyClass {
public:int data;void display() {cout << "data = " << data << endl;}
};
void processObject(MyClass *ptr){ptr -> display();
}
int main(void) {//动态分配内存创建类对象MyClass obj;obj.data = 10;processObject(&obj);return 0;
}

1.12C++类的静态成员

  • 使用 static 关键字来把类成员定义为静态的,当我们声明类的成员为静态时,无论创建多少个类的对象,静态成员都只有一个副本。

  • 静态成员在类的所有对象中是共享的,如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化

    //
    // Created by 16690 on 2024/4/22.
    //
    #include<iostream>
    using namespace std;class Box{
    public:static int objectCount;//构造函数定义Box(double len=2.0,double wid=2.0,double hei=2.0){cout << "构造函数执行" << endl;length = len;width = wid;height = hei;objectCount++;}double volume(){return length * width * height;}
    private:double length;double width;double height;
    };
    //初始化静态成员变量
    int Box::objectCount = 0;int main(void){Box box1(3.3, 1.2, 1.5);Box Box2(8.5, 6.0, 2.0);cout << "Total objects:" << box1.objectCount << endl;return 0;
    }
    
静态成员函数
  • 如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来
  • 静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问
  • 静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数
  • 静态成员函数有一个类范围,他们不能访问类的 this 指针

  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。

  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针

    //
    // Created by 16690 on 2024/4/22.
    //
    #include<iostream>
    using namespace std;class Box{
    public:static int objectCount;//构造函数定义Box(double len=2.0,double wid=2.0,double hei=2.0){cout << "构造函数执行" << endl;length = len;width = wid;height = hei;objectCount++;}double volume(){return length * width * height;}static int getCount(){return objectCount;}
    private:double length;double width;double height;
    };
    //初始化静态成员变量
    int Box::objectCount = 0;int main(void){cout << "创建对象前,共有" << Box::getCount<< "个对象" << endl;Box box1(3.3, 1.2, 1.5);Box Box2(8.5, 6.0, 2.0);cout << "Total objects:" << box1.objectCount << endl;return 0;
    }
    

http://www.ppmy.cn/ops/25419.html

相关文章

JAVA面试题分享---多线程与线程池

多线程 什么是线程?线程和进程的区别?&#xff08;了解&#xff09; 线程&#xff1a;是进程的一个实体&#xff0c;是 cpu 调度和分派的基本单位&#xff0c;是比进程更小的 可以独立运行的基本单位。 进程&#xff1a;具有一定独立功能的程序关于某个数据集合上的一次运…

Spring Boot的热部署工具“AND”Swagger测试工具

Spring Boot的热部署&Swagger测试页面的使用 热部署指的是在项目无需重启的情况下&#xff0c;只需要刷新页面&#xff0c;即可获得已经修改的样式或功能。要注意该工具一般用于开发环境&#xff0c;在生产环境中最好不要添加这个工具。 对于无需重启便可刷新这么方便的工…

手持LED弹幕,超炫特效,让你的每一次出场都耀眼夺目!

在这个快节奏的数字时代&#xff0c;沟通不再局限于言语和文字&#xff0c;就连表白、追星、晚会互动&#xff0c;甚至日常的提词都需要一点科技的火花来点燃气氛。于是&#xff0c;手持LED弹幕滚动屏&#xff0c;这个集实用与趣味于一身的神器&#xff0c;悄然成为了社交场上的…

Java23种设计模式-行为型模式之责任链模式

责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;:允许将多个对象连接成一条链&#xff0c;并沿着这条链传递一个请求&#xff0c;直到链上的某个对象能够处理该请求为止。这种模式的目的是解耦请求的发送者和接收者&#xff0c;同时允许多个对象有机会处理…

解决 Vant 框架的 Field 组件 rules 规则错误提示语不动态改变

Vant 的 Field 组件可以通过 rules 属性来设置验证表单的错误提示语&#xff0c;当提示语显示后&#xff0c;再去改变的时候&#xff0c;发现这个提示语并没有变&#xff0c; 我是在切换多语言的时候发现这个问题的&#xff0c; 解决方法就是&#xff1a;给 Field 组件添加一个…

【MySQL】MVCC的实现原理

【MySQL】MVCC的实现原理 MVCC简介事务的隔离级别读未提交&#xff08;Read Uncommitted&#xff09;概念分析 读已提交&#xff08;Read Committed&#xff09;概念分析结论 可重复读&#xff08;Repeatable Read&#xff09;概念分析结论 串行化&#xff08;Serializable &am…

缓存相关问题:雪崩、穿透、预热、更新、降级的深度解析

✨✨祝屏幕前的小伙伴们每天都有好运相伴左右✨✨ &#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; 目录 1. 缓存雪崩 1.1 问题描述 1.2 解决方案 1.2.1 加锁防止并发重建缓存 2. 缓存穿透 2.1 问题描述 2.2 解决方案 2.2.1 布隆过…

K8S 哲学 - deployment -- kubectl【create 、 rollout 、edit、scale、set】

kubectl create kubectl rollout kubectl edit kubectl set kubectl scale 1、创建与配置文件解析 2、deploy 滚动更新 &#xff1a;template 里面的内容改变触发滚动更新 编辑该 deploy 的 配置文件 &#xff0c;加入一个 label 不会触发滚动更新 改变 nginx镜…