第4章 C++的面向对象编程

类和对象

从结构到类

结构体定义如下:

struct 结构名
{
    成员表列;
}变量名表列;

输入3门成绩,输出总成绩:

#include<iostream.h>
struct student
{
    int math;
    int english;
    int chemistry;
    int all(){
        return math+english+chemistry;
    }
}A;
void main()
{
    int a;int b;int c;
    cin>>a>>b>>c;
    A.math=a;
    A.english=b;
    A.chemistry=c;
    cout<<A.all()<<endl;
}

类是比结构更为安全的数据类型:

class 类名
{
private:
    私有成员
public:
    公有成员
protected:
    保护成员
};
//注意冒号

定义成员函数

返回类型 类名::函数名(参数列表)
{
    ……
}

方式一:成员函数的定义,在类声明时给出函数原型,而在类的外部定义函数体

class point //申明类point
{
private:
    int x;int y;
public:
    float distance();   //类的成员函数的函数原型
};
int point::distance()   //类成员函数的定义
{
    return sqrt(x*x+y*y);
}

方式二:将成员函数定义在类的内部,这样定义为内置函数。如果直接在类内部编写函数体,则称为隐式定义,如果函数仍然在外部,则需要在函数前添加incline,称为显示定义。

class point //声明类point
{
    private:
        int x;int y;
    public:
        float distance()    //定义函数
        {
            return sqrt(x*x+y*y);
        }
};
class point
{
    private:
        int x;int y;
    public:
        float distance();
};
//类的内置成员函数
incline int point::dsitance()
{
    return sqrt(x*x+y*y);
}

对象应用

声明类时直接定义对象:这种形式的对象定义是指在声明类的同时,直接定义该类的对象,在声明类的括号后直接列出对象名,并且可以定义多个对象。对象之间用逗号隔开,并且在最后一个对象的后面添加一个分号。

//声明类时直接定义对象
class point
{

    private:
        int x;int y;
    public:
        float distance()
        {
            return sqrt(x*x+y*y);
        }
}A,B;   //定义类的对象A,B
//声明类之后在定义对象
class point
{
    private:
        int x;int y;
    public:
        float distance()
        {
            return sqrt(x*x+y*y);
        }
};
point A,B;  //定义对象

定义类point,在声明类的时候直接定义对象,并且在主程序中利用类的对象使用类的成员变量和成员函数。

#include<iostream.h>
#include<math.h>
class point
{
    private:
        int x;int y;
    public:
        float distance()
        {
            return sqrt(x*x+y*y);
        }
        void init(int a,int b)
        {
            x=a;y=b;
        }
}A;
void main()
{
    point B;
    A.init(3,4);
    B.init(6,8);
    cout<<A.distance()<<"  "<<B.distance()<<endl;
}

对象的作用域

类的作用域就在括号里面。

构造函数和析构函数

对象的初始化工具——构造函数

构造函数是一种特殊的成员函数,他主要进行一些初始化工作。构造函数有以下基本性质。
- 构造函数和类的名字相同
- 构造函数不具有返回值
- 定义对象时,系统自动调用构造函数
- 构造函数是公有函数,但它不可以被显式调用。

class point
{
    private:
        int x;int y;
    public:
        float distance()    //类的成员函数
        {
            return sqrt(x*x+y*y);
        }
        point(int a,int b)  //类的构造函数,创建对象时必须指明参数
        {
            x=a;
            y=b;
        }
}A;
默认参数的构造函数
#include<iostream.h>
#include<math.h>
class point
{
    private:
        int x;int y;
    public:
        float distance()
        {
            return sqrt(x*x+y*y);
        }
        point(int a=2,int b=3)
        {
            x=a;
            y=b;
        }
};
void main()
{
    point A;    //即a=2,b=3
    point B(7); //即a=7,b=3
    point C(4,6);
    cout<<A.distance()<<" "<<B.distance()<<" "<<C.distance()<<endl;
}
对象的销毁工具————析构函数

析构函数也是一种特殊的成员函数,他执行和构造函数相反的工作,析构的特殊性质如下:
- 析构函数名称与类同名,但前面加一个“~”
- 一个类中只有一个析构函数,并且该函数不带任何参数
- 当撤销对象时编译系统自动调用析构函数
- 若程序员没有定义析构函数,编译系统自动生成析构函数
- 析构函数不可以拥有参数
- 构造函数和析构函数都不可以被显示调用,没有返回值,所以不可以指定返回类型,void也不行。

#include<iostream.h>
#include<math.h>
class point
{
    private:
        int x;int y;
    public:
        float distance()
        {
            return sqrt(x*x+y*y);
        }
        point(int a,int b)
        {
            cout<<"构造函数被调用"<<endl;
            x=a;
            y=b;
        }
        ~point()
        {
            cout<<"析构函数被调用"<<endl;
        }
};
void main()
{
    point A(2,3);   //定义对象
}
重载构造函数与拷贝构造函数

C++允许重载构造函数,所谓的重载就是允许在类中有多个构造函数。当然这些构造函数是有区别的,各个构造函数必须拥有不同的参数个数或者参数类型。

class point
{
    //重载构造函数
    public:
    point();
    point(int);
    point(int,int);
}

拷贝构造函数:依据已经存在的对象建立新的对象,该构造函数的性质有如下特点:

  • 函数名称和类名一样
  • 每个类都有一个拷贝构造函数,如果程序中没有显示定义,编译系统会自动生成一个拷贝构造函数。
  • 拷贝构造函数有一个参数,是类的对象的引用。
class point
{
    private:
    int x;int y;
    public:
    float distance()    //类的成员变量
    {
        return sqrt(x*x+y*y);
    }
    point(int a,int b)  //构造函数
    {
        x=a;
        y=b;
    }
    point(const point &p)   //拷贝构造函数
    {
        x=2*p.y;
        y=2*p.x;
    }
};
void main()
{
    point A(4,5);   //调用构造函数
    point B(A); //调用拷贝构造函数
    cout<<A.distance()<<" "<<B.distance()<<endl;
}

友元函数

类的主要特点就是数据隐藏,私有成员只可以被类的内部使用,但有时候需要在类的外部访问类的私有成员,即友元。友元函数不是类的成员函数,而是独立与当前类的外部函数,但他可以访问该类的所有成员。在类的定义中声明友元函数时,需要在函数名前面加上friend。友元函数可以定义在类的内部,也可以在外部定义。但是,这使得封装性下降,如非必要,尽量减少友元的使用。

class point
{
    private:
    int x;int y;
    public:
    float distance()    //定义成员函数
    {
        return sqrt(x*x+y*y);
    }   
    friend void init(point &,int a,int b);  //声明友元函数
};
void init(point &p,int a,int b) //函数定义
{
    p.x=a;
    p.y=b;
}
void main()
{
    int x;
    int y;
    cin>>x>>y;
    point pt;   //定义类的对象
    init(pt,x,y);   //使用友元函数
    cout<<pt.distance()<<endl;  //调用类的成员函数
}

除了一般的函数可以作为类的友元外,一个类的成员函数也可以作为另一个类的友元。这样的函数不仅可以访问本类的所有成员,还可以访问其友元类的所有成员。需要注意的是,当一个类中的某个成员函数定义为另一个类的友元函数时需要首先定义此类。

//利用类point的成员函数,定义为类line的友元函数,实现对友元的数据访问。
class line; //类的声明
class point
{
    private:
    int x;int y;
    public:
    point(int a,int b)
    {
        x=a;
        y=b;
    }
    void print(line &); //成员函数
};
class line
{
    private:
    int x1,y1;
    int x2,y2;
    public:
    line(int a,int b,int c,int d)   //构造函数
    {
        x1=a;
        x2=b;
        y1=c;
        y2=d;
    }
    friend void point::print(line &);   //声明友元函数
};
void point::print(line &p)  //友元成员定义实现对line类的数据成员的访问
{
    cout<<x<<y<<endl;
    cout<<p.x1<<p.x2<<p.y1<<p.y2<<endl;
}
void main()
{
    point A(7,8);   //数据对象
    line l(1,2,3,4);    //定义对象
    A.print(l);
}

由类生类————派生类

继承是面向对象程序设计的一个重要特性,他允许在现有类的基础上创建新的类,可以继承原有类数据和函数,同时可以添加新的成员。继承特性增加了代码的重复利用率,提高了代码开发效率。通过继承已有的一个或多个类产生一个新的类的过程称之为派生

私有继承

通过私有继承方式,基类的公有成员和保护成员变为私有性质的,则派生类的其他成员可以直接访问基类的成员。但是派生类的对象不可以访问基类的成员,同时基类的私有成员不可以被派生类所访问。

保护继承

派生类可以访问基类成员,但是派生类对象不能访问基类成员。

公有继承

派生类的其他成员可以直接访问基类的公有和保护,但派生类的外部只可以访问基类的公有成员。派生类的私有成员不能直接被访问,可以通过公有成员和保护成员间接访问。

派生类的构造函数与析构函数

派生类继承了基类的成员,实现了代码的重复利用,但是继承的目的更主要的是功能的扩充。基类的构造函数和析构函数不能被继承。如果在派生类中需要对新增加的成员进行初始化,则需要加入派生类的构造函数。同样,派生类也需要添加析构函数来实现一些结束工作。

//定义基类和派生类。查看构造函数和析构函数的调用次序。
#include<iostream.h>
class A     //定义一个类
{
    public:
    A()     //类的构造函数
    {
        cout<<"基类的构造函数"<<endl;
    }
    ~A()    //类的析构函数
    {
        cout<<"基类的析构函数"<<endl;
    }
};
class B:public A    //派生类
{
    public:
    B()     //派生类的构造函数
    {
        cout<<"派生类的构造函数"<<endl;
    }
    ~B()    //派生类的析构函数
    {
        cout<<"派生类的析构函数"<<endl;
    }
};
void main()
{
    B p;    //派生类的对象
}
多重继承

C既继承A,又继承B。按照A-B-C-C-B-A顺序打印。

#include<iostream.h>
class A
{
    public:
    A()
    {
        cout<<"基类A的构造函数"<<endl;
    }
    ~A()
    {
        cout<<"基类A的析构函数"<<endl;
    }
};
class B
{
    public:
    B()
    {
        cout<<"基类B的构造函数"<<endl;
    }
    ~B()
    {
        cout<<"基类B的析构函数"<<endl;
    }
};
class C:public A,public B
{
    public:
    C()
    {
        cout<<"派生类C的构造函数"<<endl;
    }
    ~C()
    {
        cout<<"派生类C的析构函数"<<endl;
    }
}

虚基类

如果一个派生类的基类是从一个共同的基类派生出来的,那么派生类的对象就是底层基类的间接派生,他会出现多个基类的拷贝。

class 派生类名:virtual 继承方式 基类
{

};
/*
基类-A基类-B基类-C基类-C基类-B基类-A基类-基类
若一个类由多个基类派生出来,
则虚基类的构造函数优先于非虚基类
*/
#include<iostream.h>
class base
{
    public:
    base()
    {
        cout<<"基类的构造函数"<<endl;
    }
    ~base()
    {
        cout<<"基类的析构函数"<<endl;
    }
};
class A:virtual public base
{
    public:
    A()
    {
        cout<<"基类A的构造函数"<<endl;
    }
    ~A()
    {
        cout<<"基类A的析构函数"<<endl;
    }
};
class B:virtual public base
{
    ……
};
class C:public A,public B
{
    ……
}

多态

程序的多态性是指不同的对象收到相同的消息而做出的不同动作。多态性包括运行时的多态性和编译时的多态性。
- 编译时多态性通过函数重载和运算符重载来实现。
- 运行多态性通过继承和虚函数来实现。

函数重载和运算符重载

派生类可以改写基类的成员函数,从而实现新的功能,这就是函数重载。

/*
派生类输出
基类输出
基类输出
*/
#include<iostream.h>
class A
{
    public:
    print() //类的成员函数
    {
        cout<<"基类输出"<<endl;
    }
};
class C:public A    //定义派生类C从A派生
{
    public:
    print() //派生类的成员函数
    {
        cout<<"派生类输出"<<endl;
    }
};
void main()
{
    A p1;   //基类的对象
    C p2;   //派生类对象
    p2.print(); //执行派生类对象的函数
    p1.print(); //执行基类的函数
    p2.A::print();  //执行基类的函数
}

运算符重载

重载为成员函数和重载为友元函数具有如下不同之处:
- 对于双目运算符,成员函数只带有一个参数,而友元函数带有两个参数
- 对于单目运算符,成员函数不带参数,友元函数带一个参数

1.重载为类的成员函数

函数类型 operator 运算符(参数表)
{

}

2.重载为友元函数

friend 函数类型 operator 运算符(参数表)
{

}

虚函数

虚函数是重载的另一种表现形式,它提供了一种动态机制,使程序运行更加灵活。一个基类的指针可以指向派生类的对象,但是利用基类指针调用类的函数时调用的仍然是基类的成员函数。

virtual void print()
{
    ……
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值