C++学习(20)

1、 

#include<iostream>
using namespace std;
int main()
{
   char *s="abcdefg";
   s+=2;
   fprintf(stderr,"%d\n",s);
   return 0;
}


分析:stdout-标准输出设备(printf(".."))同stdout;stderr--标准错误输出设备搜索;两者默认向屏幕输出。
但如果用转向标准输出到磁盘文件,则可看出两者区别。

stdout输出到磁盘文件,stderr在屏幕。

 

 

2、(1)首先要弄清一个基本事实,

系统分配是不会把地址0分配给你的,不管是栈上还是堆上,不管是auto还是static ,你不会得到首地址为0的变量。

然后你无法给指定地址块赋值,以下操作非法:

int *p = 0x12345678;

*p = 13;

 

(2)malloc函数为C语言中的标准函数,标准中规定:在分配内存失败时会返回“NULL Pointer”空指针,而非为初始化的指针。

 

C++在分配内存失败时会抛出BAD_ALLOC异常。

 

(3)野指针:指向垃圾内存的指针,而非空指针。

野指针产生原因

1).声明的指针未被初始化,指针默认值随机产生。创建指针应该将其初始化为NULL或者指向某一内存。

2).free和delete掉的指针未重置为NULL,free后的指针仍指向该内存,但该内存已变为垃圾内存。

另:空指针不指向任何实际的对象或函数,反过来说对象或函数的指针也不可能为空指针。

 

(4)空指针与野指针的区别,空指针也就是通常指向为NULL的指针,野指针就是指向一块未知的内存区域(可以是通过malloc或new申请空间后,释放后没有将指针置为空),也有可能定义了一个指针没有初始化,由于内存空间中的值在未赋值之前是随机数,所以也有可能诞生野指针。

 

3、关于空指针域未初始化的指针:

(1)对0x0这个地址取值是非法的;

(2)空指针可以确保不指向任何对象或函数;而未初始化指针则可能指向任何地方;

(3)空指针与任何对象或函数的指针值都不相等;

(4)Malloc在其内存分配失败时候返回的是一个NULL值;

 

4、(1)C++中支持抽象类,C#抽象类用abstract

(2)C++中可以在头文件中声明类的成员而在cpp文件中定义类的成员,在C#没有头文件且在同一处声明和定义类的成员;

(3)在c#可使用new修饰符显式隐藏从基类继承的成员;

(4)在c#中要在派生类中重新定义基类的虚函数必须在前面加override;

 

5

#include<iostream>
using namespace std;
class MyClass {
  public:
     MyClass(int i=0) {
       cout<<i;
     }
     MyClass(const MyClass &x) {
       cout<<2;
     }
     MyClass&operator=(const MyClass &x) {
       cout<<3;
       return*this;
     }
     ~MyClass(){
       cout<<4;
     }
    
};
int main()
{
  MyClass obj1(1),obj2(2);
  MyClass obj3=obj1;
  return 0;
}


分析一:

1.调用obj1的构造函数MyClass(int i =0)输出1;
2.调用obj2的构造函数MyClass(int i = 0)输出2;
3.调用obj3的复制构造函数MyClass(const MyClass&x)输出2;
4.main函数返回时分别调用obj3、obj2、obj1的析构函数输出444;

 

分析二:

若main函数中改成: MyClass obj1(1), obj2(2); MyClass obj3; obj3 = obj1; 最后执行的结果为:1203444 也就是说:拷贝构造函数发生在对象还没有创建;赋值操作符重载仅发生在对象已经创建的情况下。

 

分析三:

拷贝构造函数发生在对象还没有创建,需要创建时,如obj3;赋值操作符重载仅发生在对象已经执行过构造函数,即已经创建的情况下

 

前两个对象构造时分别输出1,2

第三个对象是这样构造的MyClassobj3 = obj1,之前没有执行过构造函数创建对象,所以这里会调用拷贝构造函数,输出2

然后三个对象依次析构,输出444

所以最终输出122444

 

6

#include<iostream>
using namespace std;
class B0 {
  public:
     virtual void  display() {
       cout<<"B0::display0"<<endl;
     }
};
 
class B1:public B0 {
  public:
     void display() {
       cout<<"D1::dispaly0"<<endl;
     }
};
 
class D1:public B1 {
  void display() {
     cout<<"D1::display0"<<endl;
  }
};
void fun(B0 ptr) {
  ptr.display();
}
 
 
int main()
{
  B0 b0;
  B1 b1;
  D1 d1;
  fun(b0);
  fun(b1);
  fun(d1);
  return 0;
}


分析:虚函数的动态绑定仅在 基类指针或引用绑定派生类对象时发生,fun的形参不是指针,所以调用哪个版本的函数编译时就已经确定,根据形参静态类型确定调用B0的成员。

 

此题的关键点在于fun函数,传入的参数是一个类的对象,这样,派生类作为参数传入的时候,会自动的类型转换为基类对象,这样,display就只是执行基类的函数了。打印B0::display()B0::display() B0::display()

 

这里使用的不是按地址传递,这样会转化为基类对象,直接调用基类的成员函数,如果是指针传递,改为B0 *ptr

ptr->display(),可以实现多态。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值