C++——类的入门

先借这个位置挂一下某大佬的博客:除了系围巾什么都会的dalao

在C++中,有一个叫做类的东西……鉴于我上课的时候大部分时间都在划水,所以只隐隐约约听到什么函数的封装啊,什么继承与派生之类的,完全不了解,眼看着就要期末了,不得不开始自救计划……


§类的格式

首先,还是一个老生常谈的问题:类,是什么,干什么的,怎么实现的?

什么是类呢?

简言之,在C++中,如果看到class关键字,那这个就是类的标志。

首先,我们选取被人吐槽嘲讽的谭书上的一道例题作为第一个栗子(其实谭书还是不错的,只是有少数错误,大家要理解毕竟这么厚的书,一点都不错还是很困难的)

选自第三版249页例题9.2:求体积

代码如下:

#include<bits/stdc++.h>
using namespace std;
class Box
{
public:
    Box(int,int,int);
    int volume();
private:
    int height;
    int width;
    int length;
};
Box::Box(int h,int w,int len)
{
    height=h;
    width=w;
    length=len;
}
int Box::volume()
{
    return(height*width*length);
}
int main()
{
    Box box1(12,25,30);
    cout<<"The volume of box1 is "<<box1.volume()<<endl;
    Box box2(15,30,21);
    cout<<"The volume of box2 is "<<box2.volume()<<endl;
    return 0;
}

输出:

The volume of box1 is 9000
The volume of box2 is 9450

嗯,先讲一个花絮吧……

所以在此也提醒大家,一定要注意标点,无论是在写语文作文、英语作文还是代码的时候都要注意标点(这里突然想到我的英语老师曾经多次批评我乱用标点,比如在举例子的时候逗号经常用错)。

首先,还是针对这段代码本身谈一谈一些个人看法。

先看看第一段,有位大佬跟我介绍——类和结构体差距不大。所以我们可以很容易在类中看到结构体的影子。比如:

Box::Box(int h,int w,int len)

这里,Box就在开头的位置顶替了Int之类的变量类型。
让我先安利一个博客: C++类(Class)总结

大家都有看到两个关键字:public和private,具体的作用,如这两个英语单词本身的意思所示:

class 类名
    {
        public:
            //公共的行为或属性

        private:
            //公共的行为或属性
    };


 ※注意:publicprivate 为属性/方法限制的关键字, private 表示该部分内容是私密的, 不能被外部所访问或调用, 只能被本类内部访问; 而 public 表示公开的属性和方法, 外界可以直接访问或者调用。
            一般来说类的属性成员都应设置为private, public只留给那些被外界用来调用的函数接口, 但这并非是强制规定, 可以根据需要进行调整;

还有---->不要忘了☞☞☞最后有一个分号//就像结构体一样


接下来,就是百度百科内容:
在现实世界中,经常有属于同一类的对象。例如,你的自行车只是世界上很多自行车中的一辆。在 面向对象软件中,也有很多共享相同特征的不同的对象:矩形、雇用记录、视频剪辑等。可以利用这些对象的相同特征为它们建立一个集合。而这个集合就称为 类是定义同一类所有对象的变量和方法的蓝图或原型。例如,可以建立一个定义包含当前档位等实例变量的自行车类。这个类也定义和提供了实例方法(变档、刹车)的实现。实例变量的值由类的每个实例提供。 因此,当你创建自行车类以后,必须在使用之前对它进行实例化。当创建类的实例时,就建立了这种类型的一个 对象,然后系统为类定义的实例变量分配内存。然后可以调用对象的实例方法实现一些功能。相同类的实例共享相同的实例方法。
除了实例变量和方法,类也可以定义 类变量和类方法。可以从类的实例中或者直接从类中访问类变量和方法。类方法只能操作类变量 - 不必访问实例变量或实例方法。系统在第一次在程序中遇到一个类时为这个类建立它的所有类变量的拷贝 - 这个类的所有实例共享它的类变量。
→→ 对象提供了模型化和信息隐藏的好处。类提供了可重用性的好处。

可以发现,这里对于函数的定义多了两个冒号!


-------------------------------------这里是分割线---------------------------------------------
上面废话了这么多,终于要进入正题了:

格式:请大家原谅懒惰的我……就观看上面安利的博客吧

然后上面那段代码,在 菜鸟教程上还有别的写法:
#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      double length;   // 长度
      double breadth;  // 宽度
      double height;   // 高度
};
 
int main( )
{
   Box Box1;        // 声明 Box1,类型为 Box
   Box Box2;        // 声明 Box2,类型为 Box
   double volume = 0.0;     // 用于存储体积
 
   // box 1 详述
   Box1.height = 5.0; 
   Box1.length = 6.0; 
   Box1.breadth = 7.0;
 
   // box 2 详述
   Box2.height = 10.0;
   Box2.length = 12.0;
   Box2.breadth = 13.0;
 
   // box 1 的体积
   volume = Box1.height * Box1.length * Box1.breadth;
   cout << "Box1 的体积:" << volume <<endl;
 
   // box 2 的体积
   volume = Box2.height * Box2.length * Box2.breadth;
   cout << "Box2 的体积:" << volume <<endl;
   return 0;
}


§类的继承和派生

还是先安利一个c++类的继承和派生

老师上课举例子说到了基因突变(我觉得还是应该感谢老师没有说出染色体变异和基因重组,要不然我会感觉到回到可怕的高三)

其实……

这个跟继承差不多吧,比如我的父母生了我,然后我从父母那里得到的性状就是继承。

然后我们可以把继承理解为一个动词,其结果是一个名词,也就是派生。


一、基本概念

1、类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。

2、派生类的声明:

class 派生类名:继承方式 基类名1, 继承方式 基类名2,...,继承方式 基类名n

{

    派生类成员声明;

};

3、一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个基类,称为单继承。直接派生,间接派生。

4、继承方式规定了如何访问基类继承的成员。继承方式有public, private, protected。如果不显示给出继承方式,默认为private继承。继承方式指定了派生类成员以及类外对象对于从基类继承来的成员的访问权限。

5、派生类继承基类中除构造和析构函数以外的所有成员。

6、派生类生成:

   吸收基类成员(除构造析构函数以外的所有成员);

   改造基类成员(根据继承方式调整基类成员的访问,函数在子类中的覆盖,以及虚函数在子类中的覆盖);

   添加新的成员;

7、公有继承

当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生类中不变,而基类的私有成员不可访问。即基类的公有成员和保护成员被继承到派生类中仍作为派生类的公有成员和保护成员。派生类的其他成员可以直接访问它们。无论派生类的成员还是派生类的对象都无法访问基类的私有成员。

8、私有继承

当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成员身份出现在派生类中,而基类的私有成员在派生类中不可访问。基类的公有成员和保护成员被继承后作为派生类的私有成员,派生类的其他成员可以直接访问它们,但是在类外部通过派生类的对象无法访问。无论是派生类的成员还是通过派生类的对象,都无法访问从基类继承的私有成员。通过多次私有继承后,对于基类的成员都会成为不可访问。因此私有继承比较少用。

9、保护继承

保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生类中,而基类的私有成员不可访问。派生类的其他成员可以直接访问从基类继承来的公有和保护成员,但是类外部通过派生类的对象无法访问它们,无论派生类的成员还是派生类的对象,都无法访问基类的私有成员。


二、派生类的构造函数和析构函数
1、派生类中由基类继承而来的成员的初始化工作还是由基类的构造函数完成,然后派生类中新增的成员在派生类的构造函数中初始化。
 
2、派生类构造函数的语法:
派生类名::派生类名(参数总表):基类名1(参数表1),基类名(参数名2)....基类名n(参数名n),内嵌子对象1(参数表1),内嵌子对象2(参数表2)....内嵌子对象n(参数表n)
{
    派生类新增成员的初始化语句;
}
注:构造函数的初始化顺序并不以上面的顺序进行,而是根据声明的顺序初始化。
 
3、如果基类中没有不带参数的构造函数,那么在派生类的构造函数中必须调用基类构造函数,以初始化基类成员。
 
4、派生类构造函数执行的次序:
   调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左到右);
   调用内嵌成员对象的构造函数,调用顺序按照它们在类中声明的顺序;
   派生类的构造函数体中的内容。

剩下的内容,大家去原博客看吧(✺ω✺)


嗯,大致就先到这里啦,之后想到还会接着写的(*╹▽╹*)


(✺ω✺),突然又想再写一点了

之前在很多有关C++类的学习中,会看到这段代码:

#include <iostream>
using namespace std;
class Point
{
public:
    void setPoint(int x, int y) //实现setPoint函数
    {
        xPos = x;
        yPos = y;
    }

    void printPoint()       //实现printPoint函数
    {
        cout<< "x = " << xPos << endl;
        cout<< "y = " << yPos << endl;
    }

private:
    int xPos;
    int yPos;
};

int main()
{
    Point M;        //用定义好的类创建一个对象 点M
    M.setPoint(10, 20); //设置 M点 的x,y值
    M.printPoint();     //输出 M点 的信息

    return 0;
}


这个注释写的挺详细的,但是还想再补充一下:

如果,我们省掉private那一部分会怎么样?

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void setPoint(int x,int y);
    void printPoint()
    {
        cout<<"x = "<<x<<endl;
        cout<<"y = "<<y<<endl;
    }
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

既然提到了,说明肯定是报错了
报错信息如下:

Compilation Failed


/usercode/file.cpp: In member function ‘void Point::printPoint()’:
/usercode/file.cpp:9:23: error: ‘x’ was not declared in this scope
         cout<<"x = "<<x<<endl;
                       ^
/usercode/file.cpp:10:23: error: ‘y’ was not declared in this scope
         cout<<"y = "<<y<<endl;
                       ^

也就是说:即使两个都在public下,x和y也不算是声明,我怀疑原因如下↓

虽然都在public中,但是……可以发现,这种写法:

void setPoint(int x,int y);

是不是很像自定义函数的申明,而自定义函数中括号中的参变量(不好意思,我也不知道叫啥)在函数外是不可以直接引用的,也就是如果之后需要,得重新定义参变量。所以,在这里也一样,如果这个函数只是申明,那么函数中的参变量既不能使用别的函数也不能被别的函数调用。


那么既然如此,如果按照自定义函数去理解,可以吗?

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void setPoint(int x,int y);
    void printPoint()
    {
        cout<<"x = "<<xPos<<endl;
        cout<<"y = "<<yPos<<endl;
    }
    void setPoint(int x,int y)
    {
        xPos=x;
        yPos=y;
    }
private:
    int xPos;
    int yPos;
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

答案还是否定的……报错信息如下:

Compilation Failed


/usercode/file.cpp:12:10: error: ‘void Point::setPoint(int, int)’ cannot be overloaded
     void setPoint(int x,int y)
          ^
/usercode/file.cpp:6:10: error: with ‘void Point::setPoint(int, int)’
     void setPoint(int x,int y);
          ^

即:函数不能被重载。

#include<bits/stdc++.h>
using namespace std;
class Point
{
public:
    void printPoint()
    {
        cout<<"x = "<<xPos<<endl;
        cout<<"y = "<<yPos<<endl;
    }
    void setPoint(int x,int y)
    {
        xPos=x;
        yPos=y;
    }
private:
    int xPos;
    int yPos;
};
int main()
{
    Point M;
    M.setPoint(10,20);
    M.printPoint();
    return 0;
}

调换顺序无影响。
输出:

x = 10
y = 20

若做如下调整:

void setPoint(int y,int x)
    {
        xPos=x;
        yPos=y;
    }


输出:

x = 20
y = 10

就局部而言,还是与函数比较相像的。

猜你喜欢

转载自blog.csdn.net/karen_yu_/article/details/78876208