??xml version="1.0" encoding="utf-8" standalone="yes"?>
PBS_VERTICAL //垂直
响应消息
PBM_DELTAPOS //一个进度条׃个指定的增量当前位置和重l栏Q以反映新的位置?
wParam=Q的WPARAMQnIncrement
lParam = 0;
q回原来的位|?
阅读全文
]]>
ofstream( const char* szName, int nMode = ios::out, int nProt = filebuf::openprot )
szName:指定要打开的文件名
nMode:指定打开的方式,有以下几U取?
--------------------------------------------------------------------------------
ios::app 数据始终d在文件的末尾Q文件的指针不移动。比如输入的?23Q在文g的末և现的?21Q先?插入文g,接下来插?Q??的前?...Q?/p>
ios::ate 数据d在文件的末尾Q文件指针会(x)UdQ比如输?23Q在文g的末ְ出现123.
ios::in 如果指定?jin)此模式Q则文g的内容不?x)被截?/p>
ios::out 打开文gQ用于输出,可以用于所有的ofstream对象
ios::trunc 如果文g已经存在Q那么文件的内容被清空
ios::nocreate 打开文g的时候不创徏文gQ意思是如果文g不存在,则函数失?/p>
ios::noreplace 不覆盖文Ӟ意思是如果文g存在Q则函数调用p|?/p>
ios::binary 以二q制方式打开文gQ默认是以文本方式打开
--------------------------------------------------------------------------------
nProt:指定文g保护规格说明Q有以下几种取?br />filebuf::sh_compat 兼容׃n模式filebuf::openprot和此U方式一?br />filebuf::sh_none 独占模式Q不׃n
filebuf::sh_read ׃nQ只L?br />filebuf::sh_write ׃nQ可以对文g执行写入操作
从文件中d数据是通过ifstream的对象进行的Q其构造函数如?br />ifstream::ifstream
ifstream( const char* szName, int nMode = ios::in, int nProt = filebuf::openprot );各参数的意义同上
对于C++的文件操作,需要先构徏ofstream和ifstreamcȝ对象Q然后通过该对象的成员函数q行文g的读写操作(例如write和read函数Q?/p>
例子Q?/p>
#include
#include
#include
using namespace std;
int main()
{
//打开文gQ如果文件不存在则创建文Ӟ然后向文件内写入数据
ofstream outFile("2.txt",ios::app);
//数据写入文?br /> outFile.write("c++Ҏ(gu)件的操作Ҏ(gu)",strlen("c++Ҏ(gu)件的操作Ҏ(gu)"));
outFile.close();
//在文件的末尾写入数据Q先文件的指针Ud末尾
outFile.open("2.txt",ios::app);
outFile.seekp(0,ios::end);
outFile.write(",重复写一ơ:(x)c++Ҏ(gu)件的操作Ҏ(gu)",strlen(",重复写一ơ:(x)c++Ҏ(gu)件的操作Ҏ(gu)"));
outFile.close();
//d文g的内容,q将其显C在屏幕?br /> ifstream inFile;
inFile.open("2.txt",ios::in);
char buffer[100];
inFile.read(buffer,99);
buffer[99]='';
for(int i=0;i<100;i++)
cout<<buffer[i];
inFile.close();
return 0;
}
C/C++~译器在内存分配时也保持?jin)数据对齐,L(fng)下例Q?/p>
struct{
short a1;
short a2;
short a3;
}A;
struct{
long
short a2;
}B;
cout<<sizeof(A)<<","<<sizeof(B)<<endl;//其它代码略去
l构体A和B的大分别是多少呢?
默认情况下,Z(jin)方便对结构体元素的访问和理Q当l构体内的元素都于处理器长度的时候,便以l构体里面最长的数据为对齐单位,也就是说Q?strong>l构体的长度一定是最长数据长度的整数倍?/strong>
如果l构体内部存在长度大于处理器位数时就以处理器位数为对齐单位?/p>
l构体内cd相同的连l元素将存在q箋的空间内Q和数组一栗?/p>
上例?
A?个shortcd变量Q各自占2字节Qd?Q??的倍数Q所以sizeof(A)=6;
B有一个longcd变量Q占4字节Q一个shortcd的变量,?字节Qd6不是最大长?的倍数Q所以要补空字节以增?实现寚wQ所以sizeof(8)=8?/p>
在C++cȝ设计中遵循同L(fng)道理Q但需注意Q空c需要占1个字节,?rn)态变?static)׃在栈中分配,不在sizeof计算范围内?/p>
假设我们有这L(fng)一个类Q?
class Base {
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
按照上面的说法,我们可以通过Base的实例来得到虚函数表?下面是实际例E:(x)
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虚函数表地址Q? << (int*)(&b) << endl;
cout << "虚函数表 — W一个函数地址Q? << (int*)*(int*)(&b) << endl;
/*q里的一点争议的个h看法*/
原文认ؓ(f)(int*)(&b)是虚表的地址Q而很多网友都_(d)Q包括我也认为)(j)Q?span style="color: red">(int *)*(int*)(&b)
才是虚表地址?span style="color: red">(int*)*((int*)*(int*)(&b))
; 才是虚表W一个虚函数的地址?/p>其实看后面的调用pFun = (Fun)*((int*)*(int*)(&b)); 可以看出,*((int*)*(int*)(&b));转成函数指针lpFunQ然后正的调用C(jin)虚函数virtual void f()?/p>
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
实际q行l果如下Q?Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3)
虚函数表地址Q?012FED4
虚函数表 — W一个函数地址Q?044F148
Base::f
通过q个CZQ我们可以看刎ͼ我们可以通过?amp;b转成int *Q取得虚函数表的地址Q然后,再次取址可以得到第一个虚函数的地址?jin),也就是Base::f()Q这在上面的E序中得C(jin)验证Q把int* 强制转成?jin)函数指针?j)。通过q个CZQ我们就可以知道如果要调用Base::g()和Base::h()Q其代码如下Q?
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
q个时候你应该懂了(jin)吧。什么?q是有点晕。也是,q样的代码看着太ؕ?jin)。没问题Q让我画个图解释一下。如下所C:(x)
注意Q在上面q个图中Q我在虚函数表的最后多加了(jin)一个结点,q是虚函数表的结束结点,像字符串的l束W?#8220;\0”一P其标志了(jin)虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。在WinXP+VS2003下,q个值是NULL。而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,q个值是如果1Q表C有下一个虚函数表,如果值是0Q表C是最后一个虚函数表?
下面Q我分别说?#8220;无覆?#8221;?#8220;有覆?#8221;时的虚函数表的样子。没有覆盖父cȝ虚函数是毫无意义的。我之所以要讲述没有覆盖的情况,主要目的是ؓ(f)?jin)给一个对比。在比较之下Q我们可以更加清楚地知道其内部的具体实现?
一般承(无虚函数覆盖Q?/strong>
下面Q再让我们来看看l承时的虚函数表是什么样的。假设有如下所C的一个承关p:(x)
h意,在这个承关pMQ子cL有重载Q何父cȝ函数。那么,在派生类的实例中Q其虚函数表如下所C:(x)
对于实例QDerive d; 的虚函数表如下:(x)
我们可以看到下面几点Q?
1Q虚函数按照其声明顺序放于表中?
2Q父cȝ虚函数在子类的虚函数前面?
我相信聪明的你一定可以参考前面的那个E序Q来~写一D늨序来验证?
一般承(有虚函数覆盖Q?/strong>
覆盖父类的虚函数是很昄的事情,不然Q虚函数变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了(jin)父类的虚函数Q会(x)是一个什么样子?假设Q我们有下面q样的一个承关pR?
Z(jin)让大家看到被l承q后的效果,在这个类的设计中Q我只覆盖了(jin)父类的一个函敎ͼ(x)f()。那么,对于zcȝ实例Q其虚函数表?x)是下面的一个样子:(x)
我们从表中可以看C面几点,
1Q覆盖的f()函数被放C(jin)虚表中原来父c虚函数的位|?
2Q没有被覆盖的函C旧?
q样Q我们就可以看到对于下面q样的程序,
Base *b = new Derive();
b->f();
由b所指的内存中的虚函数表的f()的位|已l被Derive::f()函数地址所取代Q于是在实际调用发生Ӟ是Derive::f()被调用了(jin)。这实C(jin)多?/span>?
多重l承Q无虚函数覆盖)(j)
下面Q再让我们来看看多重l承中的情况Q假设有下面q样一个类的承关pR注意:(x)子类q没有覆盖父cȝ函数?
对于子类实例中的虚函数表Q是下面q个样子Q?
我们可以看到Q?
1Q?每个父类都有自己的虚表?
2Q?子类的成员函数被攑ֈ?jin)第一个父cȝ表中。(所谓的W一个父cL按照声明序来判断的Q?
q样做就是ؓ(f)?jin)解决不同的父类cd的指针指向同一个子cd例,而能够调用到实际的函数?
多重l承Q有虚函数覆盖)(j)
下面我们再来看看Q如果发生虚函数覆盖的情c(din)?
下图中,我们在子cM覆盖?jin)父cȝf()函数Q?nbsp;
下面是对于子cd例中的虚函数表的图:(x)
我们可以看见Q三个父c虚函数表中的f()的位|被替换成了(jin)子类的函数指针。这P我们可以Q一?rn)态类型的父类来指向子c,q调用子cȝf()?jin)。如Q?
Derive d;
Base1 *b1 = &d;
Base2 *b2 = &d;
Base3 *b3 = &d;
b1->f(); //Derive::f()
b2->f(); //Derive::f()
b3->f(); //Derive::f()
b1->g(); //Base1::g()
b2->g(); //Base2::g()
b3->g(); //Base3::g()
安全?br />每次写C(j)++的文章,d不了(jin)要批判一下C++。这文章也不例外。通过上面的讲qͼ怿我们对虚函数表有一个比较细致的?jin)解了(jin)。水可蝲舟,亦可覆舟。下面,让我们来看看我们可以用虚函数表来q点什么坏事吧?
一、通过父类型的指针讉K子类自己的虚函数
我们知道Q子cL有重载父cȝ虚函数是一件毫无意义的事情。因为多态也是要Z函数重蝲的。虽然在上面的图中我们可以看到Base1的虚表中有Derive的虚函数Q但我们Ҏ(gu)不可能用下面的语句来调用子cȝ自有虚函敎ͼ(x)
Base1 *b1 = new Derive();
b1->f1(); //~译出错
M妄图使用父类指针惌用子cM的未覆盖父类的成员函数的行ؓ(f)都会(x)被编译器视ؓ(f)非法Q所以,q样的程序根本无法编译通过。但在运行时Q我们可以通过指针的方式访问虚函数表来辑ֈq反C++语义的行为。(关于q方面的试Q通过阅读后面附录的代码,怿你可以做到这一点)(j)
二、访问non-public的虚函数
另外Q如果父cȝ虚函数是private或是protected的,但这些非public的虚函数同样?x)存在于虚函数表中,所以,我们同样可以使用讉K虚函数表的方式来讉Kq些non-public的虚函数Q这是很Ҏ(gu)做到的?
如:(x)
class Base {
private:
virtual void f() { cout << "Base::f" << endl; }
};
class Derive : public Base{
};
typedef void(*Fun)(void);
void main() {
Derive d;
Fun pFun = (Fun)*((int*)*(int*)(&d)+0);
pFun();
}
l束?br />C++q门语言是一门Magic的语aQ对于程序员来说Q我们似乎永q摸不清楚这门语a背着我们在干?jin)什么。需要熟(zhn)这门语aQ我们就必需要了(jin)解C++里面的那些东西,需要去?jin)解C++中那些危险的东西。不?dng)q是一U搬L(fng)头砸自己脚的~程语言?/p>
本文来自CSDN博客Q{载请标明出处Qhttp://blog.csdn.net/hairetz/archive/2009/04/29/4137000.aspx
当用一个已初始化过?jin)的自定义类cd对象d始化另一个新构造的对象的时候,拯构造函数就?x)被自动调用。也是_(d)当类的对象需要拷贝时Q拷贝构造函数将?x)被调用。以下情况都?x)调用拷贝构造函敎ͼ(x)
①、一个对象以g递的方式传入函数体:(x)q个好理解,因ؓ(f)传递给函数体的参数不是 str 而是 _str ,是str的复制品。所以必然会(x)调用拯构造函数?nbsp;
②、一个对象以g递的方式从函数返?Q相当于构造一个新的对象?br />③、一个对象需要通过另外一个对象进行初始化。:(x)同上?br />
正如(zhn)理解那?“拷贝:(x)只拷贝对象的基本属性,其他的引用不拯Q还是保留引?#8221;如果在类中没有显式地声明一个拷贝构造函敎ͼ那么Q编译器会(x)自动生成一个默认的拯构造函敎ͼ该构造函数完成对象之间的位拷贝。当对象没有指针Ӟ按照上面的规则,则一切正常,拷贝把数据复制q新对象。但当对象有指针Ӟ因ؓ(f)拷贝引用不拯Q所以新对象与旧对象他们指向的是同一个内存区Q这时当释放内存时就出现释放两次Q出错了(jin)?br />
q时需要深拯..................
所以通常我们需要自己写拯构造函敎ͼ以免出现错误?br />//////////////参考资料所得,正确与否Ƣ迎讨论?br />