由创建一个不能被继承的类引发的对象模型的思考

昨天吃饭和宽妹讨论起以前看过的如何创建一个不能被继承的类,具体实现见

http://blog.csdn.net/kuaile123/article/details/21321471

同学提到了第一种方法,说new过之后还需要delete释放内存,这样需要把析构函数也设置为private。

然后就想到能不能创建一个变量,返回此变量,而不是new一个,这样可以将析构函数设置为pubic不需要delete。宽妹说这种方法肯定行不通,因为这样创建是在栈上创建的,当返回时变量已经无效了。事实证明是可行的。

class A{
private:
	int i;
	A( int j=0 ){ 
		i=j; 
		printf("construct: %d \n",i);
	}
public:
	static A get_A0(){A a(2);return a;}
};
A a0 = A::get_A0();//调用

后讨论说他说的是返回变量的地址是有错的,上述之所以成功是因为后面调用后使用了一个复制构造函数,这样会造成效率低。然后再次写了返回变量地址的方法,如下所示:

//class A 定义里面
public:
	static A* get_A1(){A a(2); return &a; }

A* a1 = A::get_A1();//调用

显示创建是没用问题的,宽妹说调用此对象的一个成员函数肯定会出错,由此,我们添加了一个成员函数,如下所示:

//class A 定义里面
public :
int f(){
				printf("%d \n",i);
				return i;
	}
//调用
a1->f();

输出为:

construct: 2
4062396

而new的调用是这样的:

static A* get_A2(){ return new A(3); }
A* a2 = A::get_A2();
a2->f();

输出为:

construct: 3
3

显示堆上创建的调用是没有错的,栈上创建的调用结果是错误的。因为栈上创建的是局部变量,用new是在堆上创建的,如果不手动释放会一直存在,而在栈上创建的出了作用域会失效,所以在堆上创建调用函数时没有问题的。

但是依然可以打印说明仍然可以进入函数,但是只是打印成员数据时出错,此时我们讨论了C++对象模型,宽妹认为成员函数是不放置在类对象里的,而是经过混淆放置于一个全局的位置,所以虽然类对象是错误的,但是依然可以调用成员函数。为此又写了一个调用方法来证实,将随便一个变量的地址赋值给类对象,照样能打印,数据还是此变量的值,如下所示:

int i =100;
	A* a = reinterpret_cast<A*>(&i);
	a->f();

输出为:

100

由此可见没有调用构造函数直接访问了i的地址。我们翻了《C++对象模型》这本书,讨论了出现这种结果的原因,C++对象模型中,只有非静态数据成员被放置在每一个类对象中,而其他的如静态数据成员、静态和非静态函数成员都是放置于类对象外,可以理解为一个类的空间中,每个对象只是共享同一份。这样也就解释了为什么类对象错误但是依然能够调用类成员的原因。当创建一个类变量返回该变量的地址时,复制该指针,而当退出此函数时随即此变量已经失效,a1指针实际上指向的是一块无效的栈空间,当调用函数f()时,只是从类中调用,不经过类对象a1,f()中需要对象的数据成员i,就到认为正确的地址空间去找,a1+数据成员在a1中的偏移,而此时此段可能已经被改写,此时不会返回正确的结果。同理,我们随便将一个变量的地址强制转换为类对象的指针,此时也是上述的流程,上述巧合是因为第一个声明的成员变量地址和类对象地址是一致的,而且对象中的i和所声明变量都是int型,读取时都会读取i的地址,当我们将变量设置为float等,此时就会有截断等,打印出的也不是变量的值。


有些问题在书上看到过,但是距离用理论来分析还是有一定距离,幸而周围有几个小伙伴,尤其是宽妹,让我对一些东西的理解更深一些。三个臭皮匠顶个诸葛亮,O(∩_∩)O哈哈~






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值