定义一个类的时候,就是定义了一个具体的数据类型,若要使用这种类,就要将其实例化,这就是定义该类的对象。
此前的对象就是指的数据对象,之后表示专门的类的实体。
先定义类类型在定义对象,各对象用逗号分割。
类名 对象名列表;
或者 class 类名 对象名列表;//兼容了C语言
或者定义类类型的同时定义列表。
class 类名{ ...} a,b,c;
类的名字可以省略,但之后无法再调用这个类。
定义对象的时候,会为其分配存储空间。
一般形式:
类名 *对象指针变量
对象指针变量 = new 类名
例如:
Point *p;
p = new Point;
这种形式得到的对象是无名的,需要用指针来访问这个对象,反之会返回一个0,表示内存不足,无法生成一个对象。
delete p;
有new一定要用delete;
对象名.成员名
对象名.成员函数(参数列表)
p1 = &A;让p指向类A
对象指针->成员名
对象指针->成员函数(参数列表)
类名 &引用名 对象名
例如:CLASS A, &B = A;
表示B是A的引用。
对象之间可以互相赋值,将所有的数据成员都进行赋值。静态的数据成员不行。
这两个对象必须是同类的才行。
成员中若有指针,则只是指针之间的赋值,指针指向的对象不会发生改变。
若函数的形参是对象的时候,实参也必须是对象,不会对其做隐性的类型转换。
对象作为参数传递的时候对空间要求很高,若考虑空间开销,减少类作为形参的传递。
此时形参对实参形成了一个副本,会造成空间的占用,且不能直接对原对象做出改变。
当形参是对象的指针,实参也必须是指向对象的指针。
此时传入的是对象的地址,能够在函数中对其改变。且不会生成副本,减少了空间的浪费。
当形参是一个对象的引用的时候,实参要求是同类的对象,与指针一样,也可以传回变化后的对象。
函数声明: void func(Data a, Data *p, Data c)
函数调用: func(A,&B,C) 传入的就是,复制了A,B的地址,和C的引用。
若不希望改变原有的内容,在Data前面加上const限定。
函数返回地址和引用可以减少额外空间的开销,但是返回对象则会复制一个临时对象出来,占用额外的空间。
!!!!!在函数内部新建的临时变量,返回其指针或者引用,这些变量在函数结束后会消亡,因此不能作为指针和引用的返回,只能按照返回值返回,除非在函数外面,直接给需要用到的地址才不会产生临时变量。
若类里面数据成员全部是共有的,可以在定义变量的时候,对所有成员进行初始化。
构造函数在创建的时候会自动执行,这时候可以对内部所有进行初始化。
构造函数可以没有形参,同时没有函数值。
构造函数的函数名字要和名字相同。
class Cuboid{
public:Cuboid(int l,int h, int d);int length,height;
private:int depth;};Cuboid::Cuboid(int l, int h, int d){length = l;height = h;depth = d;
}int main(){Cuboid a(1,2,3) //定义对象a同时初始化
}
构造函数自动执行,且只执行一次,不能被调用,也不需要被调用,需要声明为共有的,在类外部创建对象的时候要调用之。不提倡在里面加入与初始化无关的内容。构造函数应当对每个成员都初始化,不然容易引用未初始化的成员会报错。
参数的个数次序和类型需要相同,形参与实参。
也可以用构造函数初始化列表的形式初始化,如下所示:省略了大部分的行数。
Cuboid::Cuboid(int l, int h, int d):length(l),height(h),depth(d);
初始化列表只能在定义的时候使用,也可以加上大括号执行一些函数内容,
但不推荐在初始化中执行与初始化无关的内容;
有时候必须使用初始化列表进行参数的初始化:
当一个类里面的成员是另一个类的类型,同时另一个类中没有默认构造函数[指没有参数的构造函数],的时候,若这个类使用的不是参数的初始化列表,就会报错。
要尽可能减少使用成员,初始化成员。按照与成员的声明一致的次序初始化成员。
初始化的表达式可以是任意的表达式。
构造函数允许被重载,可以使用不同的方式初始化函数。这些重载的构造函数的形参列表互异。
但建立对象的时候,只会调用其中之一。
初始化参数可以使用默认值,简化代码,对使用者也更加友好。
初始化参数必须要在类里面说明,不能在类外说明。
若所有都给出了初始化参数,就和无参数的构造函数会冲突,引起歧义。
所以不能同时使用构造函数的重载和带默认参数的构造函数。
无参数和全默认参数的构造函数成为默认构造函数。若没有任何构造函数,系统可以生成一个构造函数称为:合成默认构造函数。
可以通过定义构造函数,实现其他类型到该类类型的隐式转换。这种转换的构造函数只能有一个参数。
例如,可以将字符串作为构造函数的输入,将字符串中的值赋给类中的变量,就实现了从字符串到类类型的转换。
一般形式为
类名 (const 指定数据类型& obj)
a = 类名字(变量名字)
比如
a = Data("String");或者 Data a("String")
str = "String"
a=Data(str)
用explic 修饰构造函数,可以防止隐式的转换,在转换的时候使用显式的转换,防止错误。
拷贝构造函数,用一个对象初始化另一个对象。
class Point { //Point类
public:Point() : x(0), y(0) { } //默认构造函数Point(const Point& r) : x(r.x), y(r.y) { } //复制构造函数Point(int a,int b) : x(a), y(b) { } //带参数构造函数
private:int x,y;
};
复制构造对象传入的是一个同类的对象的引用,一般都用const对其进行限定,防止原来的对象被修改。
类名 对象名字(同类对象) 同时定义新的对象,并用原来的对象对其初始化。
赋值和复制,赋值需要先定义,而复制不需要。
若不定义复制构造函数,系统会生成一个合成复制构造函数,即使定义了其他的构造函数,系统也会生成一个复制构造函数,操作为:将新对象初始化原对象的副本。逐个成员复制。
编译器将现对象的每个非静态的数据成员,依次的复制到正在创建的对象中。
内置成员直接复制其值;类类型成员使用其自带的复制构造函数进行复制,若有数组成员,将复制数组,每个元素到新对象中。
函数的形参为对象类型,而非指针和引用的时候,会按值传递,调用复制构造函数产生一个副本。传入函数。
以对象类型作为返回值的时候,也会产生一个副本复制,也要用到复制函数。
类类型的数组的时候,将会用默认构造函数初始化数组,若使用大括号初始化,则需要使用复制初始化来初始化每个元素。
正是因为有了复制构造函数,才可以传递对象和返回对象。
若复制对象,但没复制资源内容,则称为浅复制。只复制地址数,但不复制其存储的东西。
深复制,既复制地址,也会将地址指向的内容一起复制,生成一个副本。
若同时撤销原本和副本,就会将同一个存储空间撤销两次,此时系统会报错。
系统自动生成的是浅复制,这是其不足之处。
当类中含有指针的时候,显得尤为重要。
本文发布于:2024-02-01 22:25:34,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170679753639828.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |