1.new 在现有的堆上再次分配
char *cp = new char[100],ch[50];
int *p = new(cp) int ;
*p=58;
delete p;
cp = cp+sizeof(int);
delete cp;//错误,不能释放两次
int *p = new(ch) int ; //利用现有栈空间重新分配
delete *p ; //错误,不能释放栈空间
2.一些喜欢出错的运算符重载(括号、用户自定义)
#include <iostream>
using namespace std;
class test{
friend ostream & operator << (const ostream &o,const test &t);
};
ostream& operator << (ostream &o,const test &t){
cout <<"test"<<endl;
return o ;
}
class Time{
public:
int operator()() { //小括号重载 版本0 注意和下面用户自定义转换的区别
cout <<"bracket"<<endl;
return h*3600 + m*60 + s;
}
operator test() { //用户自定义转换 1.用户定义的转换不能指定返回类型 2.“Time::operator test”: 必须返回一个值
cout <<"cast test"<<endl;
static test t;
//return t; //返回class test的一个引用
}
void operator()(int h, int m, int s) { //小括号重载 版本3
this->h = h;
this->m = m;
this->s = s;
}
private:
int h;
int m;
int s ;
} ;
int main(int argc,char**argv){
Time t;
t(1,1,1) ; //小括号重载 ,并带有三个参数
cout<<t()<<endl;//小括号重载 版本0
cout<< test (t) ;
return 0;
}
3.const 修饰函数
const char* const foo(char const * const str) const
第一个const表示返回类型为const,也就是不能把此函数的返回值当作左值来使用。
第二个const表示指针的不可变性,但在这是可以省略,因为返类型已经是const。
第三个cosnt表示str的常量性,也就其内容是不能改变,可以写在其前面的char的前面。
第四个cosnt表示str的指针的常量性,也就是此指针不能指向别的地址。
第五个cosnt表示此函数的常量性(前提是类的成员函数),不能修改所在类的数据成员。
更详细的用法,参考:http://blog.youkuaiyun.com/Eric_Jo/article/details/4138548
4.采用const_cast 进行转换
用法:const_cast <type_id> (expression)该运算符用来修改类型的const或volatile属性。除了const 或volatile修饰之外, type_id和expression的类型是一样的。
· 常量指针被转化成非常量指针,并且仍然指向原来的对象;
· 常量引用被转换成非常量引用,并且仍然指向原来的对象;
· 常量对象被转换成非常量对象。
下面还是用代码来说明问题
代码一:
const int m = 15;
const int *const_p = &m;
int *p = const_cast<int*> (const_p) ;
*p = 18;
cout << *p<<*const_p<<m; ;
输出结果: 181815
代码二:
int m = 15;
const int *const_p = &m;
int *p = const_cast<int*> (const_p) ;
*p = 18;
cout << *p<<*const_p<<m; ;
输出结果: 181818
代码三:
const int m = 15;
const int &mconst = m;
int &mnc =const_cast<int&>(mconst ); //或 int &mnc =const_cast<int&>(m);
mnc = 80;
cout << mnc <<mconst <<m;
输出结果:808015
这真是一件奇怪的事情,但是这是件好事:说明C++里是const,就是const,外界千变万变,我就不变。不然真的会乱套了,const也没有存在的意义了。
IBM的C++指南称呼“*modifier = 7;”为“未定义行为(Undefined Behavior)”。所谓未定义,是说这个语句在标准C++中没有明确的规定,由编译器来决定如何处理。
位运算的左移操作也可算一种未定义行为,因为我们不确定是逻辑左移,还是算数左移。
再比如下边的语句:v[i] = i++; 也是一种未定义行为,因为我们不知道是先做自增,还是先用来找数组中的位置。
对于未定义行为,我们所能做的所要做的就是避免出现这样的语句。对于const数据我们更要这样保证:绝对不对const数据进行重新赋值。
更详细的内容参考: http://www.cnblogs.com/ider/archive/2011/07/22/cpp_cast_operator_part2.html
5.不可以拷贝的对象
C++中不可拷贝的对象一般为IO对象,不可拷贝的原因:io对象操作各种不同的输入输出设备的句柄,如果允许复制,会出现两个不同的对象操作同一个设备句柄,如果其中一个析构了,该设备被关闭,但另一个对象仍使用该句柄,会导致不可预测的运行期错误,是危险的。因此io对象不允许复制。
不可复制的实现:
在C++中,类的拷贝主要是通过拷贝构造函数和赋值函数,再者就是为拷贝专门实现的成员方法。由于拷贝构造函数和赋值函数在用户为提供的情况下是由C++编译器自动生成的,而且是public成员,因此默认的C++类都有拷贝功能。因此,可以显示的将构造函数和赋值函数设为私有成员,
在此留一下问题: 友员friend 是可以访问私友成员,如果让友员也不访问部分私友成员呢???
6.RTTI(Run-Time Type Identification)
先看看下面一段代码:
#include <iostream>
using namespace std;
class A{
int m[15];
public:
virtual void prinA(){cout <<"this is A"<<endl;}
};
class B: public A{ //若换成虚继承,会有什么情况?
public:
virtual void prinB(){cout <<"this is B"<<endl;}
};
void fun_1(A* pa){
B* pb = dynamic_cast<B*>(pa);
if(pb==NULL){
pa->prinA();
}else{
pb->prinB();
}
}
void fun_2(A* pa){
B*pb=NULL;
if(typeid(*pa)== typeid(B) ){
pb= static_cast<B*>(pa) ;
pb->prinB();
}else{
pa->prinA();
}
}
int main(){
//cout <<sizeof(A)<<sizeof(B);//6464
A * pa =new B ;
cout <<typeid(pa).name()<<endl;
cout <<typeid(*pa).name()<<endl;
fun_1(pa);
fun_2(pa);
A* paa = new A ;
fun_1(paa);
fun_2(paa);
return 0;
}
先不用看运行结果,可以先试着做做,看看与运行结果是否一样!

运行结果:
class A *
class B
this is B
this is B
this is A
this is A
Press any key to continue . . .
至于细仔的说明,这里就不弄出来了,给一个参考的链接吧!
更多细节参考:http://www.cnblogs.com/zhyg6516/archive/2011/03/07/1971898.html
7.typeid
在揭开typeid神秘面纱之前,我们先来了解一下RTTI(Run-Time Type Identification,运行时类型识别),它使程序能够获取由基指针或引用所指向的对象的实际派生类型,即允许“用指向基类的指针或引用来操作对象”的程序能够获取到“这些指针或引用所指对象”的实际派生类型。在C++中,为了支持RTTI提供了两个操作符:dynamic_cast和typeid。
dynamic_cast允许运行时刻进行类型转换,从而使程序能够在一个类层次结构中安全地转化类型,与之相对应的还有一个非安全的转换操作符static_cast,因为这不是本文的讨论重点,所以这里不再详述,感兴趣的可以自行查阅资料。下面就开始今天我们的话题:typeid。
typeid是C++的关键字之一,等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的常量对象的引用(在头文件typeinfo中定义,稍后我们看一下vs和gcc库里面的源码),它的表达式有下图两种形式。
ISO C++标准并没有确切定义type_info,它的确切定义编译器相关的,但是标准却规定了其实现必需提供如下四种操作(在之后的章节中我会来分析type_info类文件的源码):
t1 == t2 | 如果两个对象t1和t2类型相同,则返回true;否则返回false |
t1 != t2 | 如果两个对象t1和t2类型不同,则返回true;否则返回false |
t.name() | 返回类型的C-style字符串,类型名字用系统相关的方法产生 |
t1.before(t2) | 返回指出t1是否出现在t2之前的bool值 |
8.箭头重载
#include <iostream>
using namespace std;
class A{
public:
void action(){
cout << "Action in class A!" << endl;
}
};
class B{
A a;
public:
A* operator->(){
return &a;
}
void action(){
cout << "Action in class B!" << endl;
}
void printB(){
cout << "I am B" <<endl;
}
};
class C{
B b;
public:
B operator->(){
return b;
}
void action(){
cout << "Action in class C!" << endl;
}
};
int main(int argc, char *argv[]){
B b;
//b->printB(); //error C2039: “printB”: 不是“A”的成员
b->action() ; //正确,调用 A::action()
C* pc = new C;
pc->action(); //正确,调用C::action();
C c;
c->action(); //正确,调用C::operator-> ,再调用B::operator->,再调用A::operator->,最后调用A::action()
getchar();
return 0;
}
9.等继.....