C++面向对象编程

面向对象编程有三个特征:数据抽象和封装,继承,多态。

一、数据抽象和封装

在C++中,数据抽象和封装通过类来实现。

数据抽象是一种依赖于接口和实现分离的编程技术。类的设计者必须关心类的实现,而使用该类的程序员不必了解这些细节,只需要了解该类型的接口。

封装是一种将低层次的元素组合起来形成新的,高层次实体的技术,常用的封装形式如函数,隐藏了实现细节,对外提供接口,类也是一样。

1、类的声明

类的声明仅声明类的存在,不提供实现细节。

class A;

2、类的定义

简单的来说,类就是定义了一个新的类型和一个新的作用域。类的定义形式为:

class A{
public/private/protected: 
          成员类型  成员名称;
          ...
};
2.1 访问控制关键字

public,private,protected是3个类的访问控制关键字,用于控制对类中成员的访问权限。

public:可以被使用该类型的所有代码访问。

private:只能被本类的其他成员访问。

protected:可以被类即派生类的成员访问。


2.2 类成员

类的成员可以是数据,函数,或者类型别名。

C++的一个空类会自动生成4种成员函数:默认构造函数,析构函数,拷贝构造函数和赋值函数。


3 类对象

定义了一个类,就是定义了一个类型。接着就可以定义这个类型的对象,分配存储空间。

class A a1;
A a1;

4、成员函数

每个成员函数都由一个隐含的指针this,初始为调用函数的对象的地址。当我们需要将一个对象作为一个整体引用而不是引用对象的某个成员时,常常需要使用this。


4.1 构造函数

1)默认构造函数,是指对象定义时没有提供显式初始化时的初始化操作。

2)构造函数与类同名,且没有返回类型。

3)一般使用构造函数初始化列表,来初始化对象的数据成员。Const对象或引用类型的对象,可以初始化,但不能赋值。

4)在类内部,必须声明成员函数,但可选定义。在类内部定义的函数默认为inline。

5)声明一个用默认构造函数初始化的对象时,不能使用

Sales_item  myobj();   

应使用:Sales_item myobj;

除了构造函数之外,还有3个复制控制函数:析构函数,拷贝构造函数和赋值操作符。


4.2 拷贝构造函数

1)只有单个形参,并且该形参是对本类类型对象的引用(常用const修饰),这样的构造函数成为复制构造函数。

2)不论是否自定义构造函数,编译器都会生成一个合成复制构造函数,它执行逐个成员初始化,将新对象初始化为原对象的副本。

3)有些类需要禁止复制,如iostream。这时就需要将复制构造函数声明为private并且不定义。


4.3 析构函数

1)撤销类对象时自动调用析构函数,完成资源回收

2)动态分配的对象只有在指向它的指针被删除或实际对象超出作用域时才撤销。当对象的指针或引用超出作用域时,不会运行析构函数。

3)无返回值,无形参,不能重载。

4)即使定义了析构函数,编译器也会生成合成析构函数,这是与复制和赋值的区别。


4.4 赋值操作符

重载实现

class A{
public:
        A& operator=(const A &);
}

5、智能指针

复制指针时只复制指针中的地址,而不会复制指针所指的对象,这就是通常所说的浅拷贝。这会导致一系列问题,如a,b指向同一块对象,通过a删除了对象时,就会出现悬浮指针。


为了解决这个问题,C++提出了智能指针。智能指针类中有一个计数器,和类指向的对象相关联。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。

C++ STL定义了许多智能指针:auto_ptr、unique_ptr、shared_ptr和weak_ptr。


6、static成员

1)非static数据成员存在于类类型的每个对象中。而static数据成员独立于类的对象而存在;;

每个static数据成员是与类关联的对象,并不与该类的对象相关联

只有一份,由该类所有对象共享

class Account{
public:    static double rate();//static成员函数
private:   static double interestRate;//static数据成员,仅是声明,还需在类外定义。
}


2)可以通过作用域操作符从类直接调用static成员,或通过对象,引用,指针间接调用。

double rate1 = Account::rate();

3)static成员函数只需要在类的内部声明,在类的外部实现时无需再次声明static。

  static成员函数不是任何对象的组成部分,所以没有this指针,不能声明为const,也不能声明为虚函数。


4)static数据成员不能通过构造函数初始化,而是在类的外部进行初始化。


二、继承

它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展的一种C++特性。

派生类的定义格式为:

class 派生类名称:派生类型保留字 基类名称{………};

派生类型保留字:

public(公有派生):基类的public,protected成员在派生类保持,private成员在派生类不可见。

protected(保护派生):基类的private成员在派生类中不可见,public,protected成员转为protected。

private(私有派生): 基类的private成员在派生类中不可见,public,protected成员转为private。


1、友元不能继承。

2、构造函数和复制控制成员不能继承。

3、每个派生类构造函数除了初始化自己的数据成员之外,还要初始化基类,派生类构造函数只能初始化自己的直接基类。

4、派生类析构函数不负责撤销基类对象的成员,每个析构函数只负责清除自己的成员。对象的撤销顺序与构造顺序相反:首先运行派生类析构函数,然后按照继承层次依次向上调用各基类析构函数。

5、作为基类使用的类应该具有虚析构函数,以保证在删除(指向动态分配对象的)基类指针时,根据指针实际指向的对象所述的类型运行适当的析构函数。


三、多态

多态通过虚函数来实现。

对应同样成员函数名称,在基类和派生类执行不同的函数体。 

virtual 函数返回值函数名(形参列表);//只需要声明即可

基类声明并定义虚函数之后,若派生类不重写该虚函数,则会继承基类的虚函数。若重写,则会替换基类的虚函数。

1、动态绑定

通过动态绑定,编写程序时就可以使用继承层次中任意类型的对象,无需关心对象的具体类型。

触发动态绑定的条件:

1)成员函数为虚函数。

2)必须通过基类类型的引用或者指针进行函数调用。

2、C++的类不具有多态性,指针和引用具有多态性,但指针和引用的操作复杂。为解决这个问题,C++定义包装(cover)类或句柄类(handle)。


参考:

《C++primer》 中文版(第四版)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值