C++面向对象(1)

191 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第4天

前言:C++支持面向对象的程序设计,类是C++的核心特征。关于面向对象的程序设计语言之前只接触过Java,而且学的也及其浅薄,只知道大概的概念。所以在学习C++的时候,感觉语法上和C语言基本差不多,不知道为什么在C语言之外再推出一个C++出来,直到后来才了解到C语言是面向过程的程序设计语言,而C++则是面向对象的。

C++类与对象

类的定义

  • 类的定义是以class关键字开头,后跟类的名称
  • 关键字public确定类成员的访问属性,public表示在类的外部也可以访问,也可以指定private或protected
#include<iostream>
using namespace std;
​
int main (){
    class box{
    public://
        double length;
        double breadth;
        double  height;
    };
}

对象的定义

类提供的对象的蓝图,所以对象是根据类来创建的,定义类的对象 就像 定义基本类型的变量一样

box a;
box b;

访问数据成员

  • 类中的数据方法称为类的成员
  • 对于类的对象的公共数据成员可以用直接成员访问运算符 . 访问
  • 实例:
#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);
};
​
double box::get(void){
    return length * breadth * height;
}
​
void box::set(double len,double bre,double hei) {
    length = len;
    breadth = bre;
    height = hei;
}
​
​
int main (){
    box box1;
    box box2;
    box box3;
    double v = 0.0 ;//体积
​
    box1.breadth=3.0;
    box1.height=2.0;
    box1.length=4.0;
    box1.get();
    cout << "box3的体积是" << v <<endl;
​
​
    box2.length=4.0;
    box2.height=2.9;
    box2.breadth=8.9;
    box2.get();
    cout << "box2的体积是" << v <<endl;
​
​
    box3.set(3.0,5.0,9.0);//因为set函数也是类的成员,所以也用.来引用
    v=box3.get();
    cout << "box3的体积是" << v <<endl;
​
}

类成员函数

在上面的例子中,set函数和get函数都是类成员函数,这里再详细介绍一下:类成员函数是把定义和原型写在类定义内部的函数,就像类中定义其他变量一样,它可以操作任意类的对象,可以访问对象中的所有成员。

class box{
    public:
    double length;
    double breadth;
    double height;
    double get (void){
        return length * breadth * height;
    }
};

成员函数可以定义在类的内部,也可以使用范围解析符 :: 来定义.

注意:在 ::运算符之前必须使用类名

class box {
    public :
    double get (void);
};
​
double box::get (void){
      return length * breadth * height;
}

创建一个对象,对象调用成员函数

box box1;
box1.get();

类访问修饰符

数据封装是面向对象编程的重要特点,它防止函数直接访问类内部成员。通过在类中标记访问修饰符 public、protected、private来指定类成员的访问限制。(默认是私有)

class box{
  public:
    //公有成员
  protected:
    //受保护的成员
  private:
    //私有成员
};
  • public:公有成员,在类的外部是可访问的

  • private:私有成员,在类的外部是不可访问的,只有类和友元函数可以访问私有成员

    • 实际操作中,一般在私有定义数据,公有定义函数,方便在类的外部也可以调用这些函数
#include<iostream>
using namespace std;
​
class box{
public:
    double length;
    void setwidth(double);
    double getwidth(void);
​
private:
    double width;
};
​
void box::setwidth(double wid) {
    width=wid;
}
​
double box::getwidth() {
    return width;
}
​
int main (){
    box box1;
    //设置长度,因为length是公有的,直接访问即可
    box1.length= 2.0;
    cout << box1.length <<endl;
    //设置宽度,因为width是私有的,所以要借助内部公有的成员函数设置
    box1.setwidth(10.0);
    box1.getwidth();
    cout << box1.getwidth() <<endl;
    return 0;
    
}
  • protected:被保护的成员,和私有成员相似,不同点是被保护的成员在其子类中可以访问
  • 继承中的特点:有public,protected,private三种继承特点,相应的改变了基类的访问属性

类的构造函数&析构函数

构造函数

  • 是类的一种特殊的成员函数,在每次类创建新对象时执行
  • 构造函数的名称和类名相同,不会返回任何类型,也不会返回void
  • 构造函数可用于某些成员变量设置初值
#include<iostream>
using namespace std;
​
class Line{
public:
    void setlength(double);
    double getlength(void);
    Line();//构造函数
private:
    double length;
};
​
void Line::setlength(double len) {
    length=len;
}
​
double Line::getlength() {
    return length;
}
​
Line::Line(){
    cout << "Object is being created" << endl;
}
​
int main(){
    Line Line;
​
    Line.setlength(10.0);
    cout << Line.getlength() << endl;
    return 0;
}
  • 构造函数也可以带有参数,在创建对象时给对象赋初值
Line Line (double){
    cout << "Object is being created, length = " << len << endl;
    length = len;
}
int main (){
    Line Line(10.0);
    cout << Line.getlength <<endl
}

类的析构函数

  • 是类的一种特殊的成员函数,在每次删除所创建对象时执行
  • 析构函数的名称和类名相同前面加上~作为前缀
  • 没有返回值,不能带有参数
  • 作用:在跳出程序前(关闭文件,释放内存)前释放资源
class Line{
  public:
    Line();
    ~Line();
};
​
int main (){
    ~Line(){
        cout << "Object is being deleted" << endl;
    }
}

拷贝构造函数

是一种特殊的构造函数,在创建对象时,,使用同一类中 之前创建的对象来初始化新创建的对象。通常用于:

  • 使用另一个同类型的对象来初始化新创建的对象
  • 复制对象把它作为参数传递给函数
  • 复制对象,并从函数返回这个对象

如果类中没有定义拷贝构造函数,编辑器会自己定义一个。如果类中有指针变量,并有动态内存分配,则必须要有一个拷贝构造函数。

基本形式

类名(const 类名 &obj){
    ....
}//obj是一个对象引用,用于初始化另一个对象的
#include <iostream>
using namespace std;
​
class Line{
public:
    int getlength(void);
    Line(int len);
    ~Line();
    Line (const Line &obj);
​
private:
    int *ptr;
};
​
Line::Line(int len) {
    cout << "Object is being creating" <<endl;
    //为指针分配内存
    ptr=new int ;
    *ptr = len;
}
​
Line::~Line() {
    cout << "Object is being deleted" << endl;
    delete ptr;
}
​
int Line::getlength() {
    return *ptr;
}
​
Line::Line(const Line &obj) {
    cout << "调用构造函数 并为指针ptr分配内存" << endl;
    ptr = new int ;
    *ptr = *obj.ptr;//拷贝值
}
​
void display (Line obj){
    cout << "Line的值是" << obj.getlength() <<endl;
}
​
int main (){
    Line Line(10);
    display(Line);
    return 0;
​
}

友元函数

友元函数定义在类外部,但有权访问类的private 和 protected成员,友元函数的原型在类的定义中会出现,但友元函数并不是成员函数

友元可以是一个函数,即友元函数;也可以是一个类,即友元类(整个类及其成员都是友元)

需要在类定义中 该函数原型前使用friend关键字表示自己是友方

#include <iostream>
using namespace std;
​
class box{
    double width;
public:
    void setwidth(double);
    friend void printwidth(box box1);
};
​
void box::setwidth(double wid) {
    width = wid;
}
​
void printwidth(box box1){
    cout << box1.width <<endl;//因为是友军,所以不用借助之前的getwidth()函数,直接用这种当时获得width
}
​
int main(){
    box box1;
    box1.setwidth(10.0);
    printwidth(box1);
    return 0;
​
}

内联函数

函数功能:以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。因此不适合用内联的情况有:

  • 代码很长的(>5)
  • 函数内部使用循环语句和双开语句

如果想把一个函数定义为内联函数,要在函数名前面放置关键字inline,在调用函数前就要对函数进行定义

inline int max (int a,int b){
    return (a>b)?a:b;
}
​
int main(){
    cout << max(1,2 )<<endl;
    return 0;
}

this指针

每个对象都能通过this指针来访问自己的地址,this指针是所有成员函数的隐藏参数,所以在成员函数内部,它可以用来调用对象

  • 友元函数没有this指针,因为友元函数不是类的成员,only成员函数才有
#include <iostream>
using namespace std;
​
class box{
public:
    box(double ,double ,double );
    double getvolume(void);//计算体积函数
    int compare (box box1);
private:
    double length;
    double breadth;
    double height;
};
​
box::box(double len, double bre, double hei) {//构造函数定义
    length=len;
    breadth=bre;
    height=hei;
}
​
double box::getvolume() {
    return length * breadth * height;
}
​
int box::compare(box box1) {
    return this->getvolume() >box1.getvolume();//注意返回值是int,即返回0或1
}
​
int main (){
    box box1(3.0,4.0,5.0);
    box box2(2.0,3.9,2.0);//
​
    if(box1.compare(box2)){//box1调用比较函数,比较函数的形参是box2.函数体内box1通过this指向自己来访问自己的getvolume函数,box2直接调用getvolume函数
        cout << "Box2 is smaller than Box1" <<endl;
    }
    else
    {
        cout << "Box2 is equal to or larger than Box1" <<endl;
    }
    return 0;
​
​
}

指向类的指针

顾名思义,就是指向类的一个指针。和指向结构体的指针类似,需要用访问运算符-> ,与其他指针一样,在使用前需要对指针进行初始化

#include <iostream>
using namespace std;
​
class box{
public:
    box(double ,double ,double );
    double getvolume(void);//计算体积函数
    int compare (box box1);
private:
    double length;
    double breadth;
    double height;
};
​
box::box(double len, double bre, double hei) {//构造函数定义
    length=len;
    breadth=bre;
    height=hei;
}
​
double box::getvolume() {
    return length * breadth * height;
}
​
​
int main (){
    box box1(3.0,4.0,5.0);
    box box2(2.0,3.9,2.0);
    
    box *ptr;
    ptr = &box1;//指向对象box1
    
    cout << ptr->getvolume() <<endl;
    return 0;
​
}

类的静态成员

静态成员变量

  • 静态成员在类的所有对象中是共享的,可以使用static关键字把类成员定义为静态的。
  • 不能把静态成员的初始化放在类的定义中,但是可以在类的外部通过范围解析运算符:: 来重新声明并初始化
#include <iostream>
using namespace std;
​
class box {
public:
    static int objcount;//注意这里要设在public里
    box(double ,double ,double );
    double getvolume(void);
private:
    double length;
    double breadth;
    double height;
};
​
int box::objcount = 0;//在类的定义外初始化静态数据成员double box::getvolume() {
    return length * breadth * height;
}
​
box::box(double l, double b, double h) {
    length=l;
    breadth=b;
    height=h;
    objcount++;//每创建一个对象自加
}
​
int main (){
    box box1(1.0,2.0,3.0);
    cout << box::objcount << endl;//1
    return 0;
}

静态成员函数

如果把函数定义为静态的,就可以把函数与任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数需要使用 类名 :: 就可以访问。

  • 访问范围:可以访问静态成员数据,其他静态成员函数以及类外部的函数
  • 静态成员函数有一个类范围,他们不能访问类的this指针