实例解析C/C++疑难问题(二)

本文详细介绍了C++中强制类型转换static_cast、dynamic_cast、reinterpret_cast的区别,以及虚继承在解决多重继承二义性问题中的作用。通过实例解释了虚继承如何确保类层次结构中只有一个公共基类的副本,避免了内存中的冗余。此外,还探讨了C++中内存管理,包括静态变量、全局变量、局部变量、静态局部变量的生命周期和内存分配。文章还讨论了C++和C#在资源回收上的差异,以及C++中的数据对齐和结构体大小计算。最后,文章通过一系列问题和示例代码,讲解了C++中的指针、引用、内存分配、字符串处理、类型转换、内存区域、对象构造与析构等基础知识,揭示了C++编程中的一些常见陷阱和最佳实践。
摘要由CSDN通过智能技术生成

c++中的强制转换static_cast、dynamic_cast、reinterpret_cast的不同用法


  • 序列化

1、序列化是干什么的?

  简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。

2、什么情况下需要序列化 

a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;

3、当对一个对象实现序列化时,究竟发生了什么?

在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

Foo myFoo = new Foo(); 
myFoo .setWidth(37); 
myFoo.setHeight(70); 

  当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把它 从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的对 象。

FileOutputStream fs = new FileOutputStream("foo.ser"); 
ObjectOutputStream os = new ObjectOutputStream(fs); 
os.writeObject(myFoo); 


虚拟继承:

C++虚继承可以防止多重继承产生的二义性问题。

        虚继承,就是在被继承的类前面加上virtual关键字,这时被继承的类称为虚基类,如下面代码中的base类。虚继承在多重继承的时可以防止二义性。

    class base

    class derived1 : virutal public base

    class derived2 : virtual public base

    class derived3 : public derived1, public derived2

以上的代码如果用到了base中的某个成员变量就不会产生二义性。和#progma once在头文件中的作用类似。请看下面的例子:

#include <iostream>

using namespace std;

class Parent

{

public:

      int p;                                           // p将会被所有的子类继承,也将是二义性的根源

      inline Parent()

      {

               p = 10;

      }

};

class Child1 : public Parent

{

public:

      int c1;

      inline Child1()

      {

               p = 12;                           // p在子类Child1中被赋值为12

               c1 = 12;

      }

};

class Child2 : public Parent

{

public:

      int c2;

      inline Child2()

      {

               p = 13;                          // p在子类Child2中被赋值为13

               c2 = 13;

      }

};

class GrandChild : public Child1, public Child2

{

public:

      int grandchild;

      // p显然也存在于GrandChild中,但是到底是12,还是13呢?这就产生了二义性

      inline GrandChild()

      {

               grandchild = 14;

      }

 };

int main(void)

{

      GrandChild* pGC = new GrandChild();

      cout << pGC->p << endl;

      return 0;

}

上面程序是不能通过编译的,编译器输出的错误信息如下:

…: error C2385: 'GrandChild::p' is ambiguous

…: warning C4385: could be the 'p' in base 'Parent' of base 'Child1' of class 'GrandChild'

…: warning C4385: or the 'p' in base 'Parent' of base 'Child2' of class 'GrandChild'

正如编译器告诉我们的那 样,GrandChild::p是模棱两可,它被Child1继承了即Child1中包含了一个Parent subobject,也被Child2继承了即Child2中也包含了一个Parent suboject,然后GrandChild又同时继承了Child1和Child2,根据“derived class中要保持base class的完整原样性原则”,因此GrandChild包含了两个ParentObject。所以当pGC->p时,编译器根本无法确定是调用Child1::p还是Child2::p,由此边产生了模棱两可的情形。怎么解决这样的问题呢?答案就是用虚继承或者叫虚基类的方式。

在上面的示例程序中做如下改动:

class Child1 : public Parent       ->     class Child1 : virtual public Parent

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值