C++学习(38)

1.  全局变量可以定义在可被多个.c文件包含的头文件中。

 

2.  下列程序输出:

int i;

  for(i=0;i<2;i++){

    fork();

    printf("-");

  }

分析:fork()系统调用的特性,fork()系统调用是Unix下以自身进程创建子进程的系统调用,一次调用,两次返回,如果返回是0,则是子进程,如果返回值>0,则是父进程(返回值是子进程的pid),这是众为周知的。 还有一个很重要的东西是,在fork()的调用处,整个父进程空间会原模原样地复制到子进程中,包括指令,变量值,程序调用栈,环境变量,缓冲区,等等。

 

一共调用了6次printf,但是会输出8个-。因为父进程的输出缓冲也会被子进程复制

fork(); // i=0

printf("-");//buffer="-"

fork(); // i=1

printf("-")//+1

printf("-");

printf("-")

fork(); // i=1

printf("-");//+1

printf("-")

 

3.类的静态成员属于整个类而不是某个对象,可以被类的所有方法访问,子类当然可以访问静态成员;
静态方法属于整个类,在对象创建之前就已经分配空间,类的非静态成员要在对象创建后才有内存,所有静态方法只能访问静态成员,不能访问非静态成员
静态成员可以被任一对象修改,修改后的值可以被所有对象共享。

静态成员无多态特性;

 

静态成员由static声明,可以被任一对象修改,修改后的值可以被所有对象共享;

常量由final关键字声明,不可以修改;

 

4. 动态分配内存点击打开链接

1). malloc,calloc,realloc,free属于C函数库,而new/delete则是C++的操作符;

2).多个“alloc”的比较:

alloc:唯一在栈上申请内存的,无需释放;

malloc:在堆上申请内存,最常用;

calloc:malloc初始化为0;

realloc:将原本申请的内存区域扩容,参数size大小即为扩容后大小,因此此函数要求size大小必须大于ptr内存大小。

 

5.C++类体系中,不能被派生类继承的有(AD

A 构造函数   B 静态成员函数  C 非静态成员函数  D 赋值操作函数


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

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


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


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

 

构造原则如下:

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

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

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

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

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

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

 

 

赋值运算符重载函数不是不能被派生类继承,而是被派生类的默认的赋值运算符重载函数给覆盖了。因此赋值运算符重载函数不能被派生类继承。

 --------------------------------------------------------------------------------------------------------------------------------------

---------------------------------------------------------------------------------------------------------------------------------------

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

 

6.静态变量在整个程序的运行过程中始终都是存在的。

 

7.抽象类的特有特征就是不能实例化

1)抽象类:成员函数含纯虚函数的类成为抽象类,目的是实现多态,如:

virtual void func()=0;

2)抽象类不能直接使用(如声明一个抽象类对象),因此在实现过程中,通常将抽象类的构造函数设置尾protected,以避免上述声明抽象类对象等不合理操作。

 

补充:

抽象类是不完整的,它只能用作基类。在面向对象方法中,抽象类主要用来进行类型隐藏充当全局变量的角色。

 

抽象类具有以下特性

1)抽象类不能实例化。

2)抽象类可以包含抽象方法和抽象访问器。

3)不能用sealed修饰符修饰抽象类,因为这两个修饰符的含义是相反的。采用sealed修饰符的类无法继承,而abstract修饰符要求对类进行继承。

4)从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实际实现。

 

8.C语言程序中的整数不能是:二进制整数。

9.dynamic_cast将一个基类对象指针(或引用)cast到继承类指针,dynamic_cast会根据基类指针是否真正指向继承类指针来做相应处理,即会作一定的判断。对指针进行dynamic_cast,失败返回null,成功返回正常cast后的对象指针;对引用进行dynamic_cast,失败抛出一个异常,成功返回正常cast后的对象引用。

 

reinterpret_cast这个转换是最“不安全”的,两个没有任何关系的类指针之间转换都可以用这个转换实现。

static_cast静态转换是最接近于C风格转换,很多时候都需要程序员自身去判断转换是否安全。

const_cast这个转换好理解,可以将常量转成非常量。

 

10.0开头表示八进制,0x表示十六进制;

L:表明这个数是long int类型的,不写的话默认认为是int;

 

11.i的初始值为0,i++在两个线程里面分别执行100次,能得到最大值是:200,最小值是:2.

 

分析:i++只需要执行一条指令,并不能保证多个线程i++,操作同一个i,可以得到正确的结果。因为还有寄存器的因素,多个cpu对应多个寄存器。每次要先把i从内存复制到寄存器,然后++,然后再把i复制到内存中,这需要至少3步。从这个意义上讲,说i++是原子的并不对。

 

如此,假设两个线程的执行步骤如下:

1).线程A执行第一次i++,取出内存中的i,值为0,存放到寄存器后执行加1,此时CPU1的寄存器中值为1,内存中为0;

2).线程B执行第一次i++,取出内存中的i,值为0,存放到寄存器后执行加1,此时CPU2的寄存器中值为1,内存中为0;

3).线程A继续执行完成第99次i++,并把值放回内存,此时CPU1中寄存器的值为99,内存中为99;

4).线程B继续执行第一次i++,将其值放回内存,此时CPU1中的寄存器值为1,内存中为1;

5).线程A执行第100次i++,将内存中的值取回CPU2的寄存器,并执行加1,此时CPU2的寄存器中的值为2,内存中为1;

6).线程B执行完所有操作,并将其放回内存,此时CPU1的寄存器值为100,内存中为100;

7).线程A执行100次操作的最后一部分,将CPU2中的寄存器值放回内存,内存中值为2;

8).结束!

所以该题目便可以得出最终结果,最小值为2,最大值为200。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值