指针类型转换(非常棒非常全的一篇文章)
http://blog.csdn.net/ZHANGJIETING/archive/2010/10/20/5953634.aspx
http://tech.e800.com.cn/articles/2009/717/1247801913566_1.html
http://dev.chinaitzhe.com/c/2008-06/121481133869042.html
#include "stdafx.h"
#include <iostream>
#include <stack>
#include <deque>
using namespace std;
/*
引用与指针的区别:
(1)、引用总是指向某个对象,定义引用的时没初始化时错误的。
(2)、赋值行为的区别:给引用赋值修改的是该引用所关联的对象的值,而并不是是引用与另一个对象关联。
引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义是初始化的原因)。
*/
int main()
{
int a = 2;
int b = 3;
int &ref_a = a;
int &ref_b = b;
printf("&a=%0x &b=%0x/n", &a, &b);
printf("/n");
printf("a=%d b=%d/n", ref_a, ref_b);
printf("&a=%0x &b=%ox/n", &ref_a, &ref_b);
ref_a = b;
ref_b = a;
printf("a=%d b=%d/n", ref_a, ref_b);
printf("&a=%0x &b=%ox/n", &ref_a, &ref_b);
ref_a = ref_b; //引用的赋值操作,使两个引用指向的对象的值相等,但没有修改引用本身
printf("a=%d b=%d/n", ref_a, ref_b);
printf("&a=%0x &b=%ox/n", &ref_a, &ref_b);
/*
如果一个指针具有0值(空指针),则在指针上加0仍然是合法的,结果是另一个0值的指针。
也可以对两个空指针做减法操作,得到的结果仍然是0.
*/
int *p1 = 0;
int *p2 = 0;
printf("p1-p2=%d/n", p1-p2);
p2 = p1 + 1;
ptrdiff_t dif1 = p2 - p1;
ptrdiff_t dif2 = p1 - p2;
printf("p2-p1=%d p1-p2=%d/n", dif1, dif2);
/*解引用运算符的优先级比加法操作符高。*/
/*C++强制要求指const对象的指针也必须具有const特性,把一个const对象的地址赋值给一个普通的、非
const对象的指针的会导致编译时的错误!
(2)、不能用void×指针保存const对象的地址,而必须使用const void×类型的指针保存const对象的地址。
(3)、允许把非const对象的地址赋给指向const对象的指针,例如:
int a = 2;
const int ×p = &a;是正确的,但是我们不能通过p来修改a的值。
*/
/*我们不能保证指向const的指针所指对象的值一定不可修改!*/
/**与任何const量一样,const指针也必须在定义的时候初始化!/
}
#include "stdafx.h"
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
class Parent
{
public:
Parent(){}
Parent(int a):m_a(a){}
virtual void print()
{
printf("%d/n", m_a);
}
virtual ~Parent()
{
printf("Parent析构函数!/n");
}
private:
int m_a;
};
class Child :
public Parent
{
public:
Child(){}
Child(int a, int b):Parent(a),m_b(b){}
virtual void print()
{
Parent::print();
printf("%d/n", m_b);
}
virtual ~Child()
{
printf("Child析构函数!/n");
}
private:
int m_b;
};
int main()
{
Parent(2); //以一个int加上“函数风格”转型动作创建一个匿名Parent对象
static_cast<Parent>(4);//以一个int加上“C++风格”转型动作创建一个匿名Parent对象
/*最好使用C++风格的类型转换,这样比较容易辨识出来*/
vector<Parent*> vec;
vec.push_back(new Parent(2));
vec.push_back(new Child(3, 4));
for (vector<Parent*>::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
(*iter)->print();
}
/*
注意:上面这种形式,不会调用容器中对象的析构函数!必须自己去通过delete去调用
*/
/*只有通过这种方式才能调用析构函数*/
for (vector<Parent*>::iterator iter = vec.begin(); iter != vec.end(); iter++)
{
delete *iter;
}
vec.clear();/*同样不会调用析构函数*/
}
/*
关于STL容器存储对象的问题
请问如果我在STL容器存储的是对象,那么我在调用clear()或eara()的时候,会自动释放这个对象的内存空间吗?会执行该对象的析够函数吗?
=======================
会,析构函数也会自动调用。
但如果存储的是对象的指针,外部对象如果是在堆上分配的,需要我们自已delete
=======================
STL的容器是基于by value语意的。当你把一个元素放入容器中,在容器中存放的实际上是这个元素的一个副本(这就是为什么STL容器要求元素必须可以拷贝构造和赋值),副本所占的内存是STL容器自己分配的,所以它会自己回收这些内存,同时调用元素的析构函数。
但是如果你把指针放到容器中,clear的时候容器只负责回收指针本身所占的内存,至于指针所指向的东西,它是不管。
*/
空基类优化
class Base
{
};
int main()
{
Base base1, base2;
if(&base1 == &base2)
cerr<<"unable to occur"<<endl;
Base *p1 = new Base();
Base *p2 = new Base();
if(p1 == p2)
cerr<<"unable to occur"<<endl;
return 0;
}
但是如果有个类是继承自空基类Base的,那么不一定因为空基类的存在而使得在子类中加入一块额外的空间
#include <iostream>
#include <cstdlib>
using namespace std;
class Base {
};
class Derived : public Base
{
public:
int a;
};
int main()
{
Derived p;
if((void*)&p == (void*)&(p.a))
cout<<"good optimizer"<<endl;
else
cout<<"bad optimizer"<<endl;
system("pause");
return 0;
}
在VC2005上输出的是good optimizer,表明编译器对空基类的情况进行了优化
Effective C++笔记: 继承和面向对象设计
http://blog.csdn.net/qin529/archive/2009/07/17/4358068.aspx
C++中typename关键字的使用方法和注意事项
http://blog.csdn.net/pizzq/archive/2007/01/18/1487004.aspx
#include "stdafx.h"
#include <iostream>
#include <stack>
#include <vector>
using namespace std;
/*空白基类最优化(EBO)*/
class A{};
class B:
private A
{
private:
int m_b;
};
template <typename C>
void printElement(const C& container)
{
typename C::const_iterator iter(container.begin());
for (; iter != container.end(); ++iter)
{
cout<<*iter<<endl;
}
}
int main()
{
printf("%d %d/n", sizeof(A), sizeof(B));
vector<int> vec;
for (int i=0; i<4; ++i)
{
vec.push_back(i+1);
}
printElement(vec);
}