C++面向对象的程序设计

1,前言

C++程序与设计是我上学期的我们专业开的一门限选课,开始就挺想学的,结果阴差阳错的没选上。“那就旁听吧”,我对自己说。两节课之后,我又咕咕了。。。这学期开了数据结构,选上后才发现C++是先选课,因此,就不得不重拾《C++程序设计(谭浩强)》开始一段一段的撸代码。写这篇博客呢,主要是为了自己做笔记,当然,若能给大家带来帮助,那我自然是双倍的快乐啦。之后呢,我也会陆续跟进老师讲的内容,写一篇关于数据结构的博客,希望以此共勉!

2,概述

以类对象为基本构成单位的程序称为基于对象的程序,而面向程序则还有更多要求。面向对象的程序设计共有四个主要特点:抽象,封装,继承和多态性。

  • 抽象:类是用来定义对象的抽象类型
  • 封装:函数名作为类对象的对外接口
  • 继承:派生类继承基类的基本特征
  • 多态性:由继承产生的不同的派生类面对同一消息会做出不同的响应

在基于对象的程序设计的基础上,利用继承和多态性,就是面对对象的程序设计。因此,就形成了新的观念,即
对象=数据+算法
程序=(对象+对象+···)+消息

3,类

3.1类的声明

格式与结构体的声明比较相似,如下

class Student                                                   //声明类
{
    private:
    int num;
    char name[20];
    char sex;
    public:
    void display()
    {
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
        cout<<"sex:"<<sex<<endl;
    }
};
Student stud1,stud2;                                           //定义对象

在面向对象的程序设计中,一般把所有的数据指定为私有,把需要让外界调用的函数设为公有
typedef可以为系统固有或者自定义的数据类型取别名,但并不是定义了一种新的数据类型,对于给类,其格式为

typedef class Student STUDENT;

3.2成员函数的外部定义

如果在类的定义中既不指定public,也不指定private,则默认为私有的。其中成员函数也可以在类的外部定义,如:

class Student
{
    private:                                             //私有数据不能被外界调用
    int num;
    char name[20];
    char sex;
    public:
    void display();
};
void Student::display()                                  //“::”作用域限定符
    {
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
        cout<<"sex:"<<sex<<endl;
    }
Student stud1,stud2;

在类里声明函数,在类外定义是一个良好的习惯

3.3内置成员函数

函数内部定义则默认为该函数为内置函数,外部定义则需要在函数声明和定义的之前,加上关键字inline,这样,当程序要调用成员函数时,直接将代码嵌入代码的调用点,减少时间开销

class Student
{
    private:
    int num;
    char name[20];
    char sex;
    public:
    inline void display();
};
inline void Student::display()                                  //“::”作用域限定符
    {
        cout<<"num:"<<num<<endl;
        cout<<"name:"<<name<<endl;
        cout<<"sex:"<<sex<<endl;
    }
Student stud1,stud2;

注意,即使时内置函数也并不占用对象的存储空间

3.4对象成员的引用

  1. 对象名+成员运算符,如stud1.num=1000
  2. 指针,如Student *p;cout<<p->num;
  3. 引用(别名),如Student stud1;Student &k=stud1;cout<<k.num;

3.5构造函数

构造函数是一类特殊的成员函数,它不具有任何类型,不返回任何值,它不需要用户调用它,在对象建立的时候自动执行,而要实现这一点只需将成员函数与类同名。我们通过构造函数实现对象的初始化。

#include <iostream>
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;
}
Box::volume()
{
    return (height*width*length);
}

int main()
{
    Box box1(12,13,14);                                          //类的初始化
    cout<<"The volume of this box is:"<<box1.volume()<<endl;
}

我们可以根据具体情况,对构造函数进行重载,以满足对象初始化的要求

3.6析构函数

与构造函数相反,析构函数是当对象结束使命时调用,具体来说在以下几类场合调用

  1. 在函数中的定义的对象,当函数结束调用时,对象应该释放,在对象释放之前调用
  2. 静态局部对象1在函数结束调用时不释放,只有当main函数结束时调用
  3. 全局变量离开作用域时
  4. 使用delete释放动态对象时
#include <cstring>
#include <iostream>
using namespace std;
class Student
{
public:
    Student(int,char[],char);
    ~Student();                                              //析构函数的声明
    void display();
private:
    int num;
    char name[10];
    char sex;
};
Student::Student(int n,char nam[10],char s)
{
    num=n;
    strcpy(name,nam);
    sex=s;
    cout<<name<<"'constructor called"<<endl<<endl;
}
Student::~Student()                                         //析构函数的定义
{
    cout<<name<<"'destructor called"<<endl;
}
void Student::display()
{
    cout<<"num:"<<num<<endl;
    cout<<"name:"<<name<<endl;
    cout<<"sex:"<<sex<<endl;
}
int main()
{
    typedef class Student STUDENT;
    STUDENT stud1(1010,"jianjian",'m');
    stud1.display();
    STUDENT stud2(1011,"dongdong",'f');
    stud2.display();
}

输出应为

jianjian'constructor called

num:1010
name:jianjian
sex:m
dongdong'constructor called

num:1011
name:dongdong
sex:f
dongdong'destructor called
jianjian'destructor called

Process returned 0 (0x0)   execution time : 0.545 s
Press any key to continue.

3.7对象的动态建立和释放

普通变量在程序结束后才会释放,若想要随时释放。我们可以用new动态建立,如

new Box;

这时,会开辟一片没有名字的内存,并返回这片内存的地址

Box *pt;
pt=new Box(10,10,10);

3.8对象的复制

本来运算符“=”是用来单个变量赋值的,现在被重载为对类对象之间的复制

int main()
{
    Box box[3]={{10,10,10},{10,10,11},{10,10,12}};
    box[0]=box[2];
    cout<<"The volume of this box is:"<<box[0].volume()<<endl;
}

输出为

The volume of this box is:1200

Process returned 0 (0x0)   execution time : 0.050 s
Press any key to continue.

3.9静态数据成员

静态数据成员相当于优化的全局变量。它为各对象所共有,它的值对所有对象都是一样的,它的改变对所有对象也是同步的,但是不能用初始化参数表对静态数据成员进行初始化,只能对其单独初始化

#include <iostream>
using namespace std;
class Box
{
public:
    Box(int,int);
    int volume();
private:
    static int height;
    int width;
    int length;
};
Box::Box(int w,int len)
{
    width=w;
    length=len;
}
Box::volume()
{
    return (height*width*length);
}
 int Box::height=10;                                          //静态数据成员只能在类体外进行初始化
int main()
{
    Box box[3]={{10,10},{10,11},{10,12}};
    box[0]=box[2];
    cout<<"The volume of this box is:"<<box[0].volume()<<endl;
}

3.10运算符的重载

重载的含义简单来说就是“一名多用”,格式如下
函数类型 operator 运算符名称(形参表)
{对运算符的重载处理}

如:

class Student1:public Student
{
public:
    Student1(int n,string nam ,char s,int a,string ad,int n1,string nam1 ,char s1):Student(n,nam,s),monitor(n1,nam1,s1)
    {
        age=a;
        addr=ad;
    }
    void display1();
    void show_monitor();
    Student1 operator +(Student1 &a);                          //对“+”重载的声明
protected:
    Student monitor;
    int age;
    string addr;
};
Student1 Student1::operator +(Student1 &a)                     //重载的实现
{
    Student1 b;
    b.num=num+a.num;
    b.age=age+a.age;
    b.name="王源";
    b.sex='m';
    return b;
}

一般来说,C++允许重载绝大多数运算符,包括

不能被重载的运算符只有4个

4,指针

4.1对象指针

建立对象时,系统给对象分配内存时,对象空间的起始地址就是对象的指针
定义格式如下

Time t;
Time *pt;
pt=&t;

引用格式如下

(*pt).volume();
pt->volume();

4.2指向对象成员的指针

定义格式如下

void (Time::*pt)();
pt=&Time::volume;


数据类型名 (类名::*指针变量名)(参数列表);
指针变量名=&类名::成员函数名;
指针的定义在类中有很多要求,这些方面都要匹配

  1. 函数参数的类型和参数个数
  2. 函数返回值类型
  3. 所属的类

5,继承与派生

继承是利用已有的类建立新类,而派生类就是已有基类的派生

5.1派生类的声明

class Student1:public Student                                    //声明基类为Student
{
public:
    void display1();                                             //新增加的成员函数
private:
    int age;                                                     //新增加的成员数据
    string addr;
};
void Student1::display1()
{
    cout<<"age:"<<age<<endl;
    cout<<"address:"<<addr<<endl;
}

5.2派生类的访问属性

派生类的继承方式包括三类:公用继承,私有继承,受保护继承

在基类中的访问属性继承方式在派生类中的访问属性
privatepublic不可访问
privateprivate不可访问
privateprotected不可访问
publicpublicpublic
publicprivateprivate
publicprotectedptotected
protectedpublicprotected
protectedprivateprivate
protectedprotectedprotected

5.3派生类的构造函数

声明派生类如下

class Student1:public Student
{
public:
    Student1(int n,char nam[10] ,char s,int a,string ad):Student(n,nam,s)           //构造函数声明格式
    {
        age=a;
        addr=ad;
    }
    void display1();
private:
    int age;
    string addr;
};
void Student1::display1()
{
    cout<<"num:"<<num<<endl;
    cout<<"name:"<<name<<endl;
    cout<<"sex:"<<sex<<endl;
    cout<<"age:"<<age<<endl;
    cout<<"address:"<<addr<<endl<<endl;
}

注意在声明这个构造函数时,基类的构造函数已经存在,并且基类的参数也已经存在,故直接调用实参,不再调用形参,更不再需要加上数据类型
若修改主函数为

int main()
{
    Student1 a(1010,"jian",'m',21,"hit");
    Student1 b(1011,"dong",'f',20,"hit");
    a.display1();
    b.display1();
}

则会输出

jian'constructor called
dong'constructor called
num:1010
name:jian
sex:m
age:21
address:hit

num:1011
name:dong
sex:f
age:20
address:hit

dong'destructor called
jian'destructor called

Process returned 0 (0x0)   execution time : 0.254 s
Press any key to continue.

5.4子对象

在对象之中内嵌的对象,就是子对象,即对象中的对象
如在派生类的成员数据中就可以定义基类的对象

class Student
{
public:
    Student(int,string,char);
    ~Student();                                             
    void display();
    int num;
    string name;
    char sex;
};

class Student1:public Student
{
public:
    Student1(int n,string nam ,char s,int a,string ad,int n1,string nam1 ,char s1):Student(n,nam,s),monitor(n1,nam1,s1)
    {
        age=a;
        addr=ad;
    }
    void display1();
    void show_monitor();
private:
    Student monitor;
    int age;
    string addr;
};

在main函数中,运行

int main()
{
    Student1 a(1010,"jian",'m',21,"hit",1009,"liu",'m');
    Student1 b(1011,"dong",'f',20,"hit",1009,"liu",'m');
    a.show_monitor();
    a.display1();
    b.display1();
}

在codeblocks中可以输出

jian'constructor called
liu'constructor called
dong'constructor called
liu'constructor called

monitor:liu

num:1010
name:jian
sex:m
age:21
address:hit

num:1011
name:dong
sex:f
age:20
address:hit

liu'destructor called
dong'destructor called
liu'destructor called
jian'destructor called

Process returned 0 (0x0)   execution time : 0.061 s
Press any key to continue.

注意不能在声明派生类时初始化子对象,因为类是抽象数据类型。执行派生类的构造函数的顺序是

  1. 调用基类的构造函数,完成对基类数据成员的初始化
  2. 调用子对象的构造函数,完成子对象的初始化
  3. 执行派生类构造函数本身,完成派生类的数据的初始化

一般形式为:
派生类构造函数名(总参数表):基类构造函数名(基类参数表),子对象(子对象参数表)
{派生类新增的数据成员初始化语句}

这个链接有更详尽的介绍
C++有子对象的派生类的构造函数

5.5多重继承

若一个派生类需要继承几个不同的基类,则需要多重继承
格式为:
派生类构造函数名(总参数表):基类1构造函数名(参数表),基类2构造函数名(参数表),基类3构造函数名(参数表)
{派生类新增成员初始化}


  1. 局部变量 静态局部变量 全局变量与静态全局变量 ↩︎

  • 17
    点赞
  • 58
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值