C++学习笔记(三)

来源:互联网 发布:notepad js格式化插件 编辑:程序博客网 时间:2024/06/06 04:02

10.类与对象

 

10.1   定义位于类声明中的函数自动成为内联函数。(一般是短小的函数)

            也可以在类声明之外,使用inline限定符将类方法成为内联函数(类声明中不用inline限定符)

 

10.2   const成员函数

创建一个const类,如

const Stock land=Stock(“aaa”,5);

land.show();            //非法,因为不允许修改land,程序不知道show()会不会修改land

解决方法:

在类声明中,声明   void show() const;

定义                              voidStock::show()  const{}

 

应该尽量使用const成员函数。(承诺不修改对象数据的函数)

 

10.3 析构函数

如果构造函数使用了new, 析构函数必须使用delete

 

10.4 接受一个参数的构造函数允许使用赋值语法将对象初始化为一个值。

 

10.5 this是指向当前对象的指针,*this是当前对象。使用this->variety访问数据成员。

 

10.6对象数组

创建没有显式初始化的对象时,系统会调用默认构造函数。

 

10.7  类作用域

不能在类声明时将数据成员设置成常量(const)。因为类声明时没有创建,不占用内存。

constint Months=12;     //不允许

但是可以使用: static const int Months=12;  允许,因为Months在静态变量存在一起。

也可以使用枚举:enum{Months=12}; int array[Months];   Months只是一个符号名称,不产生变量。

 

11  使用类

11.1  运算符重载

            returntype operatorop(argumentlist)

例如:Timeoperator*(const Time& t)const;               //重载了*运算

 

11.2 友元

友元函数常用与运算符重载。

            创建友元函数

首先将原型放到类声明里面,在原型前面加上firend关键字

friendTime operator*(double m, const Time & t);

友元函数在类声明里面,但是不是类的成员函数。具有成员函数同等的访问权限。

然后编写函数定义,因为不是成员函数,所以不需要Time::限定,也不需要关键字friend.

            Time operator*(double m, const Time& t);

11.3  转换函数

            转换函数必须是类方法。转换函数不能指定返回类型。转换函数不能有参数。

例如,转换为double类型的函数原型:

            operator double();

 

11.4 总结

定义运算符函数时,如果要使第一个操作数不是类对象,则必须使用友元函数。

非类成员函数后面不能使用const。如

friendTime operator*(double m, const Time & t)const;    红色的const是不允许的

 

 

12 类和动态内存分配

12.2 静态类成员函数

使用static关键字。不能通过对象调用静态成员函数,也不能使用this指针。只能使用类名和作用域解析符调用。

如类String的静态成员函数HowMany()调用:

intcount=String::HowMany();                        //和java的类似

 

            静态类成员函数只能访问静态数据成员。

 

12.3 在构造函数使用new

            a.在构造函数使用new来初始化指针,在析构函数就要使用delete。

            b.new和delete必须相互兼容。new-delete, new[]-delete[]

c.如果有多个构造函数,必须以相同的方式使用new,要么new,要么new[]。因为析构函数只有一个,只能使用delete或者delete[],构造函数要与析构函数兼容。

d.应定义一个复制构造函数,通过深度复制将一个对象复制给另一个对象。(防止对象中含有指向new的指针,浅层复制只复制指针,深度复制能够将指针指向的内容也复制,预防析构函数对同一个指针多次使用delete)

e.应定义一个赋值运算符,进行深度复制。

 

12.5 定位new运算符

            定位new运算符能够在指定的内存位置分配内存。

            delete与常规的new运算符配合使用,但是不能与定位new运算符配合。

            使用定位new运算符创建的对象,需要显式调用析构函数。

例如:

char *buffer=new char[512];

Test *pc1, *pc2;

pc1=new(buffer)Test;              //在buffer中创建了一个Test对象

pc2=new Test;                        //在堆中创建了一个Test对象

delete pc2;                           

pc1->~Test();                           //显式调用析构函数



13 类继承


class sub_class : publicparent_class

{};

派生类继承基类,基类类派生出派生类。  (父类派生子类,子类继承父类)

 

13.1 构造函数

派生类需要自己的构造函数,可以根据需要添加自己的数据成员和成员函数。

派生类的构造函数必须给新数据成员和继承的成员提供数据。

派生类不能直接访问基类的私有成员,所以派生类构造函数必须使用基类构造函数。

创建派生类对象时,程序首先创建基类对象。

 

派生类构造函数要点:

a.首先创建基类对象;b.派生类构造函数应通过成员初始化列表将基类信息传递给基类构造函数;c.派生类构造函数应初始化新增的数据成员。

 

创建派生类对象,程序先调用基类构造函数,在调用派生类构造函数。派生类对象过期,程序先调用派生类对象的析构函数,再调用基类的析构函数。

 

派生类对象构造函数定义:

derived::derived(type1x, type2 y) : base(x,y)     //derived派生类,base基类

{

}

 

13.1.4 派生类与基类的特殊关系

            a.派生类可以使用基类的方法

            b.基类指针可以再不进行显式类型转换的情况下指向派生类对象,引用同理。

            RatedPlayer继承了TableTennisPlayer类

            RatedPlayer rplayer(1140,”Tom”,”Smith”,ture);

            TableTennisPlayer &rt = rplayer;         //基类引用指向派生类对象

            TableTennisPlayer *pt= &rplayer;       //基类指针指向派生类对象

            rt.name();

            pt->name();

            指向派生类对象的基类指针(或引用),只能调用基类的方法,不能调用派生类的方法。

 

13.3 多态公有继承

            多态就是同一方法的行为随上下文而异。

            实现多态公有继承:在派生类重新定义基类的方法;使用虚方法。

            虚方法在方法声明前加上关键字virtual。方法在基类声明为虚后,在派生类自动成为虚方法。(在派生类使用关键字virtual的作用是指出哪些方法是虚方法)

            基类声明虚析构函数,是为了确保释放派生类对象时,按照正确的顺序调用析构函数。

 

注意:如果在派生类重新定义基类的方法,应将基类方法定义为虚方法。这样,程序将根据对象类型而不是引用或者指针的类型(如指向派生类对象的基类指针或引用)来选择方法。为基类声明一个虚函数也是惯例。

 

为何使用虚析构函数?

如果析构函数不是虚的,那么程序只会调用对应于指针类型的析构函数。指向派生类对象的基类指针或引用就是特殊情况。使用虚析构函数可以确保正确的析构函数序列被调用。

 

13.4 动态联编与静态联编

            在编译过程进行联编就是静态联编。编译器在生成能够在程序运行时选择正确的虚方法的代码,就是动态联编。

 

13.4.1 指针和引用类型的兼容性

        通常,C++不允许将一种类型的地址赋值给另一种类型的指针。但是指向基类的指针可以指向派生类,不必显式类型转换。(向上强制转换)

 

13.4.2 虚函数与动态联编

            编译器对非虚方法使用静态联编;对虚方法使用动态联编。

            如果在派生类需要重新定义基类的方法,就将它设置为虚犯法,否则设置为非虚方法。(虚方法比非虚方法效率低)

 

13.4.3 虚函数注意事项

            a.构造函数不能是虚函数。

            b.析构函数应该是虚函数,除非类不做基类(不派生)。通常给一个基类提供一个虚析构函数,即使它不需要析构函数。

            c.友元不能是虚函数,因为友元不是类的成员,只有类成员才能是虚函数。

            d.如果派生类没有重新定义函数,将使用该函数的基类版本。如果派生类位于派生链,则将使用最新的虚函数版本,例外是基类版本是隐藏。

            e.重新定义将隐藏方法。重新定义不会生成函数的两个重载版本,而是隐藏了基类版本。

            如果重新定义继承的方法,应确保与原来的原型完全相同。但是可以修改返回类型。

            如果基类声明被重载了,则应在派生类中重新定义所有的基类版本。

 

13.5 访问控制:protected

            对于外部世界来说,保护成员与私有成员相似;对于派生类来说,保护成员与公有成员相似。(派生类可以直接访问基类的保护成员,但是不能访问基类的私有成员)

13.6 抽象基类

            当类声明中包含纯虚函数,则不能创建该类的对象。包含纯虚函数的类只用作基类。要成为真正的ABC(abstract base class),必须只好包含一个纯虚函数。

virtual double Area() const=0;                 //纯虚函数,在虚方法后面加上”=0”

            纯虚函数在类中声明,但是可以不定义。(就是不用具体实现)

13.7 继承和动态内存分配

a.派生类不使用new,则不用显式定义析构函数、复制构造函数、赋值运算符。

            b.派生类使用了new,派生类中必须显式定义析构函数、复制构造函数、赋值运算符。

0 0
原创粉丝点击