木之夏  
海纳百川,有容乃大;壁立千仞,无欲则刚

在c++中类的抽象主要是根据类的属性,以及类的方法进行创建;

方法的抽象主要是设置类的函数,以时钟为例,如:settime(); showtime()

类的属性抽象如时钟的一些特有属性: 如: hour ,  minute ,  second

 

类定义的语法:

class 类名称

{

public :

   公有成员(外部接口)

private:

   私有成员

protected:

      保护型成员

};

类的公有成员,和私有成员,以及保护型成员。

 

下面建立一个时钟的类:

建立时钟类主要需要先声明公有函数,以及私有属性等;

#include <iostream>
using namespace std;

class Clock
{
public:
    void setTime(int Newhour, int Newminute, int Newsecond);
    void showTime();

private:
    int hour = 0, minute = 0, second = 0;

};

 

建立类的方法;

类的方法创建主要是,使用类名:: 函数名()

建立两个Clock的函数

void Clock::setTime(int Newhour, int Newminute, int Newsecond)
{
    hour = Newhour;
    minute = Newminute;
    second = Newsecond;

}
void Clock::showTime()
{
    cout << hour << ":" << minute << ":" << second << "\n";

}

类的函数定义使用, 类型 :: 函数名称

 

如何实例化对象以及调用类函数

int main()
{
    Clock myClock;//实例化对象
    myClock.setTime(11, 20, 03); //设定对象的时间
    myClock.showTime(); //显示时间
}

 

类的内联函数的使用

类成员函数也可以是内联函数,但是前提是需要充分的简单;

 

 

 

类的构造函数的使用

构造函数是在对象创建的时候初始化的函数,构造函数是一种特殊的成员函数,对对象的变量进行初始化工作。

构造函数:是隐含的构造函数

构造函数也是类的成员函数;

如果我们不定义构造函数,系统会自定义生成一个构造函数,但是如果我们想要自己定义一个构造函数,可以以对象名为函数名 定义一个构造函数;

如:Clock(int hour, int minute, int second);

 

 

 

但是如果声明了构造函数,需要在在将函数体写上,以保证系统可以正常的调用;

如果只有声明没有函数体,这样会导致系统报错;

注意: 构造函数不能指定返回的数据类型,因为构造函数是不具有返回值的函数;

 

构造函数体的定义:

// 构造函数的自定义
Clock::Clock(int Nhour, int Nminute, int Nsecond):
    hour(Nhour),minute(Nminute),second(Nsecond){
}

默认构造函数的定义

如何在程序中定义一个没有参数的构造函数呢?

没有参数的构造函数就在程序中定义一个同名函数没有参数,然后初始化的函数;

这样的构造函数被称为默认的构造函数,在实例化对象时如果不指定初始化参数就会调用该默认的构造函数;

函数的定义:

Clock();

函数的实现;

Clock::Clock() :
hour(0), minute(0), second(0) {

}

委托构造函数

由于前面介绍的默认构造函数,可是是否每次都需要重复定义两个类似的构造函数进行初始化?

委托构造函数的好处除了写代码简单以外,还有一个特点是保证了代码的一致性;

委托构造函数就是在实现无参数的构造函数时,使用已经建立好的有参数的构造函数;如下:

 

代码record:

// 构造函数的自定义
Clock::Clock(int Nhour, int Nminute, int Nsecond):
    hour(Nhour),minute(Nminute),second(Nsecond){

}
Clock::Clock() :Clock(0,0,0){

}
#include <iostream>
using namespace std;

class Clock
{
public:
    Clock(int hour, int minute, int second);
    Clock();
    void setTime(int Newhour, int Newminute, int Newsecond);
    void showTime();

private:
    int hour = 0, minute = 0, second = 0;
};


// 构造函数的自定义
Clock::Clock(int Nhour, int Nminute, int Nsecond):
    hour(Nhour),minute(Nminute),second(Nsecond){

}
Clock::Clock() :Clock(0,0,0){

}


void Clock::setTime(int Newhour, int Newminute, int Newsecond)
{
    hour = Newhour;
    minute = Newminute;
    second = Newsecond;

}
void Clock::showTime()
{
    cout << hour << ":" << minute << ":" << second << "\n";

}


int main()
{
    Clock myClock(0,0,0);//实例化对象
    Clock c;
    c.showTime();
    myClock.setTime(11, 20, 03); //设定对象的时间
    myClock.showTime(); //显示时间
    return 0;
}

 

 

复制构造函数:

复制构造函数是一种特殊的构造函数,其形参为本类的对象引用,作用是用一个已经存在的对象去初始化一个同类的新对象;

语法形式:

class 类名 {

public :

    类名(形参);//构造函数

    类名(const  类名 &对象名);//复制构造函数

    //       ...

};

类名::类( const  类名 &对象名)//复制构造函数的实现

{    函数体    }

 

注意:这里面const主要的作用是数据的单向传递;

隐含的复制构造函数

如果程序员没有为类声明拷贝初始构造函数,则编译器将会自己生成一个隐含的复制构造函数

这个构造函数的主要功能是:用作为初始值的对象的每个成员的数值初始化将要建立对象的数据成员;

如何阻止对象的复制构造

在C++89 中的做法是: 将复制构造函数声明为private 且不提供函数实现;

在C++11 中的实现:

用“=delete”指向编译器,不生成默认的复制构造函数

  例:

class Point {   //Point 类的定义

public:

    Point(int xx=0, int yy=0) { x = xx; y = yy; }    //构造函数,内联

    Point(const Point& p) =delete;  //指示编译器不生成默认复制构造函数

private:

    int x, y; //私有数据

};

 

复制构造函数被调用的三种方式

1、定义一个对象时,以本类中另外一个对象作为初始值,发生复制构造

2、如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造

3、如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个无名对象,传递给主调函数,此时发生复制构造。

 

实例代码;

下面代码主要是使用了三种调用复制构造函数的情况;

#include <iostream>
using namespace std;

class Point
{
public :
    Point();
    Point(int xx,int yy);
    int getX();
    Point(const Point& p);


private: //私有数据
    int x, y;

};


int Point::getX()
{
    return x;
}

// 成员函数的实现
Point::Point(int xx, int yy): x(xx),y(yy){}
Point::Point():Point(0,0){}


Point::Point(const Point& p) {
    x = p.x;
    y = p.y;
    cout << "calling the copy constructor" << endl;
}

//形参为Point对象类函数
void fun1(Point p) 
{
    cout << p.getX() << endl;
}

//返回值为Point类对象的函数
Point fun2() {
    Point a;
    return a;
}

int main()
{
    Point a; //第1个对象a
    Point b(a); // 情况1: 用A 初始话B。第一次调用拷贝构造函数
    cout << b.getX() << endl;
    fun1(b);// 情况2 :对象B作为fun1的实参。第2次调用拷贝构造函数
    b = fun2();//情况3: 函数返回值是类对象,函数返回时,调用拷贝构造函数
    cout << b.getX() << endl;

    return 0;
}

运行结果:

calling the copy constructor
0
calling the copy constructor
0
calling the copy constructor
0

 析构函数

析构函数主要是完成对象删除前的一些删除工作

在对象生存期结束的时候系统会自动调用他,然后再释放此对象所属的空间

如果程序员没有指定析构函数,系统将自动创建一个析构函数,此析构函数为空

析构函数的声明以及实现主要是使用~类名

实现如下:

 

需要注意析构函数不能有返回语句、不能有参数表、不能有返回类型

 类的组合

类的组合主要是,新建一个芯类时,使用之前见了好的类进行组合;

就是将原有的类组合后创建新的类

所以部件类中的私有成员在类的外面是无法访问的

组合类对象的初始化

组合类的初始化需要比较多的参数,不仅需要原有类参数的初始话同时也需要本类的初始话参数

声明的方式

声明形式:

类名::类名(对象成员所需的形参,本类成员形参)

:对象1(参数),对象2(参数)......

{

//函数体其他语句

}

 

首先对构造函数的初始化列表列出的成员(包括基本对象成员和对象成员)进行初始化,初始化次序是类体中成员定义的顺序;

成员对象构造函数调用的顺序,按对象成员的声明顺序,先声明者先构造;

初始列表中的未出现的成员对象,调用默认构造函数(即无形参)初始化

处理完初始化列表后。在执行构造函数的函数体;

类的组合的实例

 类的组合的语法;

//类的组合

class Line { //Line类的定义

public: //外部接口

Line(Point xp1, Point xp2);

Line(Line &l);

double getLen() { return len; }

private: //私有数据成员

Point p1, p2; //Point类的对象p1,p2

double len;

};

 

类的组合构造函数:

 

//组合类的构造函数

 

Line::Line(Point xp1, Point xp2) : p1(xp1), p2(xp2) {

 

cout << "Calling constructor of Line" << endl;

 

double x = static_cast<double>(p1.getX() - p2.getX());

 

double y = static_cast<double>(p1.getY() - p2.getY());

 

len = sqrt(x * x + y * y);

 

}

 

Line::Line (Line &l): p1(l.p1), p2(l.p2) {//组合类的复制构造函数

 

cout << "Calling the copy constructor of Line" << endl;

 

len = l.len;

 

}

 

program demo record

 

#include <iostream>
#include <cmath>
using namespace std;

class Point //定义point类
{
public :
    Point();
    Point(int xx,int yy);
    int getX();
    int getY();
    Point(const Point& p);


private: //私有数据
    int x, y;

};


int Point::getX()
{
    return x;
}
int Point::getY()
{
    return y;
}



// 成员函数的实现
Point::Point(int xx, int yy): x(xx),y(yy){}
Point::Point():Point(0,0){}


Point::Point(const Point& p) {
    x = p.x;
    y = p.y;
    cout << "calling the copy constructor" << endl;
}

// line 类的组合
class Line {
public ://外部接口
    Line(Point xp1, Point xp2); //有参数的构造函数
    Line(Line& l);//复制构造函数
    double getLen() { return len; }
private:
    Point p1, p2; //点类型的对象
    double len;
};

//组合类的构造函数
Line::Line(Point xp1,Point xp2):p1(xp1),p2(xp2){
    cout << "calling constructor of Line  " << endl;
    double x = static_cast<double>(p1.getX() - p2.getX());
    double y = static_cast<double>(p1.getY() - p2.getY());
    len = sqrt(x * x + y * y);
    }
// 组合类的复制构造函数
Line::Line(Line& l) :p1(l.p1), p2(l.p2) {
    cout << "Calling the copy constructor of Line" << endl;
    len = l.len;
}


int main()
{
    Point myp1(1, 1), myp2(4, 5); //建立point 对象
    Line line(myp1, myp2); //建立line 对象
    Line line2(line); // 利用复制构造函数建立一个line对象
    cout << " The lenth of line is:";
    cout << line.getLen() << endl;
    cout << "the lenth of line is:";
    cout << line2.getLen() << endl;
    return 0;
}

 运行结果;

calling the copy constructor
calling the copy constructor
calling the copy constructor
calling the copy constructor
calling constructor of Line
calling the copy constructor
calling the copy constructor
Calling the copy constructor of Line
The lenth of line is:5
the lenth of line is:5

 

类的前向引用声明

当一个类需要引用另外一个类时,需要在引用类之前声明该类

但是当两个类相互引用时,就需要使用到类的前向引用声明了;

但是前向引用声明不是万能的

 

前向引用声明只为程序中引用一个标识符,但具体声明在其他地方

实例;

class B;  //前向引用声明

class A {

public:

  void f(B b);

};

class B {

public:

  void g(A a);

};

前向引用声明注意实现

1、前向引用声明虽然可以解决一些问题,但是并不是万能的

2、在提供一个完整的类的声明之前,不能声明该类的对象,也不能在内联成员函数中使用该类的对象;

3、在使用类的前向引用声明时,只能使用类的声明符号。不能涉及类的任何细节否则就会出错;

错误demo:

class Fred; //前向引用声明

class Barney {

   Fred x; //错误:类Fred的声明尚不完善

};

class Fred {

   Barney y;

};

 

posted on 2021-02-14 22:43  木之夏  阅读(226)  评论(0编辑  收藏  举报