C++学习(15)

来源:互联网 发布:怎么样利用网络挣钱 编辑:程序博客网 时间:2024/06/17 13:17

一、静态成员的特点:

(1)static数据成员在类的内部声明,但只能在类的外部定义,在类的外部不能指定static,在类的定义时候进行初始化;

(2)static数据成员只能在类的外部进行初始化特例:当整型const static数据成员被常量表达式初始化时,就可以在类的内部进行初始化,但还需要在外部进行定义)。

(3) static数据成员可以是该成员所属的类类型,而非static数据成员只能自身类的引用或者指针。

(4)static数据成员可以用作类成员函数的默认实参。

(5)static数据成员的值可以改变。

 

二、静态成员和非静态成员的区别:

(1)静态变量使用 static 修饰符进行声明,在类被实例化时创建,通过类和对象都可以进行访问;

(2)不带有 static 修饰符声明的变量称做非静态变量,在对象被实例化时创建,通过对象访问;

(3)一个类的所有实例的同一静态变量都是同一个值,同一个类的不同实例的同一非静态变量可以是不同的值。

(4)静态函数的实现里不能使用非静态成员,如非静态变量、非静态函数等。

 

三、静态成员函数的特点:

(1) static成员函数没有 this 形参,它可以访问所属类的 static 成员,但不能访问非 static 成员。

(2)static成员函数既可以在类的内部定义,也可以在类的外部定义,在外部定义时,不能重复指定static保留字。

(3)static成员函数不能声明为虚函数,不能实现动态绑定

(4)static 成员函数不能声明为const,因为const是针对this而不是const而言的

(5)构造函数、析构函数不能为静态函数。

 

 ————————————————————————————————————————————————————

————————————————————————————————————————————————————

 

1、定义一个输出文件流对象,并打开ddu文件夹下的abc.dat文件方法是:

ofstream  fout;

fout.open(“d:\\du\\abc.dat”);

 

2、在重载运算符函数时,只能使用成员函数重载的运算符有=、()、[]、->、new、delete

重点参考学习点击打开链接 


3、short a[10]={0};sizof(a)返回的是20

分析:sizeof是求字节,short是2字节,2*10=20

#include<iostream>#include<string.h>usingnamespace std;intmain() {         short a[10]={0};         cout<<sizeof(a)<<endl;}


sizeof 运算符

【1】sizeof 运算符 返回一条表达式或者一个类型名字所占的字节数。满足右结合律,所得值是size_t 类型的常量表达式, 注: 数组下标类型是size_t , 定义在头文件stddef中。

【2】sizeof( type )----所占用的空间,

sizeofexpr -----返回的是表达式结果类型的大小

注:sizeof(*p)等价于sizeof *p,在sizeof的运算对象中解引用一个无效指针仍然是一种安全行为、

【3】对数组执行sizeof 运算符得到整个数组所占空间的大小,等价于 对数组所有的元素各执行一次。

此时数组名不会转换成指针来处理

【4】对string 对象 或者 vector 对象指向 sizeof 运算只返回该类型固定部分的大小,不会计算对象中元素占用多少空间

 

4、下列代码,输出结果为 6,10

#include<iostream>#include<string.h>usingnamespace std;intmain() {         unsigned long pulArray[]={6,7,8,9,10};         unsigned long *pulPtr;         pulPtr=pulArray; //将指针pulPtr指向数组第一个元素         *(pulPtr+2)+=2; //把数组第三个元素+2         printf("%d,%d\n",*pulPtr,*(pulPtr+2)); //pulPtr仍然指向第一个元素,所以为6,而第三个元素已经被改变为8+2=10}

分析:*(pulPtr+2)+=2等价于*(pulPtr+2)+2 =pulPtr[2]+2 =pulArray[2]+2 =10

此时pulPtr中存的地址并没有改变,所以仍然指向第1个元素,最后输出是第3个元素,此时已经被上面的计算改为10了,所以结果是10。

 

补充:*(p++) *(p+1)的区别:前者取*p的值,p的指向+1变为下一位;后者取下一位的值,但指向不会变为下一位。

 

5、64位系统下,*p=NULL,和*p=new char[100],sizeof(p)各为多少?88

分析:系统可寻址的地址长度。系统=操作系统。

32位操作系统为4,64位操作系统为8.

#include<iostream>#include<string.h>using namespace std;int main() {         char *p1=NULL;         char *p2=newchar[100];         cout<<sizeof(p1)<<""<<sizeof(p2)<<endl;}


 

6C++类体系中,不能被派生类继承的有:构造函数,赋值操作函数。

分析:(构造函数不能被派生,但是可以被调用。如果父类重新定义了构造函数,也就是没有默认的构造函数时,子类创建自己的构造函数时候必须显示调用父类的构造函数。)

(赋值运算符重载函数“不是不能被派生类继承,而是被派生类默认的赋值运算符重载函数给覆盖,这就是C++赋值运算符重载函数不能被派生类继承的真正原因) 对赋值操作函数分析可参考:点击打开链接

 

缺省构造函数、拷贝构造函数、拷贝赋值函数、析构函数这4种成员函数被称为特殊的成员函数,不能被继承。

 

 

补充:

编译器总是根据类型来调用类成员函数。但是一个派生类的指针可以安全地转化为一个基类的指针。这样删除一个基类的指针的时候,C++不管这个指针指向一个基类对象还是一个派生类的对象,调用的都是基类的析构函数而不是派生类的。如果你依赖于派生类的析构函数的代码来释放资源,而没有重载析构函数,那么会有资源泄漏。所以建议的方式是将析构函数声明为虚函数。也就是delete a的时候,也会执行派生类的析构函数。

 

一个函数一旦声明为虚函数,那么不管你是否加上virtual修饰符,它在所有派生类中都成为虚函数。但是由于理解明确起见,建议的方式还是加上virtual 修饰符。

 

构造方法用来初始化类的对象,与父类的其它成员不同,它不能被子类继承子类可以继承父类所有的成员变量和成员方法,但不继承父类的构造方法)。因此,在创建子类对象时,为了初始化从父类继承来的数据成员,系统需要调用其父类的构造方法。

 

如果没有显式的构造函数,编译器会给一个默认的构造函数,并且该默认的构造函数仅仅在没有显式地声明构造函数情况下创建。

 

构造原则如下:

1).如果子类没有定义构造方法,则调用父类的无参数的构造方法。

2).如果子类定义了构造方法,不论是无参数还是带参数,在创建子类的对象的时候,首先执行父类无参数的构造方法,然后执行自己的构造方法。

3).在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数,则会调用父类的默认无参构造函数。

4).在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类自己提供了无参构造函数,则会调用父类自己的无参构造函数。

5).在创建子类对象时候,如果子类的构造函数没有显示调用父类的构造函数且父类只定义了自己的有参构造函数,则会出错(如果父类只有有参数的构造方法,则子类必须显示调用此带参构造方法)。

6).如果子类调用父类带参数的构造方法,需要用初始化父类成员对象的方式,

 

 

原创粉丝点击