Visual C++开发工具与调试技巧整理
1、如何在Release状态下进行调试
Project->Setting=>ProjectSetting对话框,选择Release状态。C/C++标签中的Category选General,Optimizations选Disable(Debug),Debut info选Program Database。在Link标签中选中Generate debug info复选框。
注:只是一个介乎Debug和Release的中间状态,所有的ASSERT、VERIFY都不起作用,函数调用方式已经是真正的调用,而不查表,但是这种状态下QuickWatch、调用队列跟踪功能仍然有效,和Debug版一样。
2、Release和Debug有什么不同
Release版称为发行版,Debug版称为调试版。
Debug中可以单步执行、跟踪等功能,但生成的可执行文件比较大,代码运行速度较慢。Release版运行速度较快,可执行文件较小,但在其编译条件下无法执行调试功能。
Release的exe文件链接的是标准的MFC DLL(Use MFC in a shared or static dll)。这些DLL在安装Windows的时候,已经配置,所以这些程序能够在没有安装Visual C++ 6.0的机器上运行。而Debug版本的exe链接了调试版本的MFC DLL文件,在没有安装Visual C++6.0的机器上不能运行,因为缺相应的DLL,除非选择use static dll when link。 (北大青鸟烟台文化宫中心 - )
3、ASSERT和VERIFY有什么区别
ASSERT里面的内容在Release版本中不编译,VERIFY里面的内容仍然翻译,但不再判断真假。所以后者更安全一点。例如ASSERT(file.Open(strFileName))。
一旦到了Release版本中,这一行就忽略了,file根本就不Open()了,而且没有任何出错的信息。如果用VERIFY()就不会有这个问题。
4、Workspace和Project之间是什么样的关系
每个Workspace可以包括几个project,但只有一个处于Active状态,各个project之间可以有依赖关系,在project的Setting..中可以设定,比如那个Active状态的project可以依赖于其他的提供其函数调用的静态库。
5、如何在非MFC程序中使用ClassWizard
在工程目录下新建一个空的.RC文件,然后加入到工程中就可以了。
6、如何设置断点
按F9在当前光标处增加一个断点和取消一个断点。
另外,在编辑状态下,按Ctrl+B组合键,弹出断点设置对话框。然后单击【Condition…】按钮弹出设置断点条件的对话框进行设置。
7、在编辑状态下发现成员变量或函数不能显示提示是如何打开显示功能
这似乎是目前这个Visual C++ 6.0版本的一个bug,可按如下步骤使其正常,如再出现,可如法炮制:
(1)关闭Project
(2)删除“工程名.ncb”文件 (3)重新打开工程
8、如何将一个通过ClassWizard生成的类彻底删除
首先在工作区的FileView中选中该类的.h和.cpp文件,按delete删除,然后在文件管理器中将这两个文件删除,再运行ClassWizard,这时出现是否移走该类的提示,选择remove就可以了。
9、如何将在workspace中消失的类找出来
打开该类对应的头文件,然后将其类名随便改一下,这个时候工作区就会出现新的类,再将这个类改回原来的名字就可以了。
10、如何清除所有的断点
菜单【Edit】->【Breakpoints…】,打开“Breakpoints”对话框,单击【Remove All】按钮即可。快捷键是“Ctrl + Shift + F8”。
11、如何再ClassWizard中选择未列出的信息
打开“ClassWizard”对话框,然后切换到“Class Info”页面。改变“Message filter”,如选择“Window”,“Message”页面就会出现Window的信息。 12、如何检测程序中的括号是否匹配
把光标移动到需要检测的括号前面,按快捷键“Ctrl + ]”。如果括号匹配正确,光标就跳到匹配的括号处,否则光标不移动,并且机箱喇叭还会发出一声警告。
13、如何查看一个宏(或变量、函数)的定义
把光标移动到要查看的一个宏上,就比如说最常见的DECLARE_MAP_MESSAGE上按一下F12(或右键菜单中的相关菜单),如果没有建立浏览文件,就会出现提示对话框,按【确定】按钮,然后就会跳到该宏(或变量、函数)定义的地方。
14、如何添加Lib文件到当前工程
单击菜单【Project】->【Settings…】弹出“Project Setting”对话框,切换到“Link”标签页,在“Object/library modules”处输入Lib文件名称,不同的Lib之间用空格格开。
15、如何快速删除项目下的Debug文件夹中临时文件
在工作区的FileView视图中选中对应的项目,单击右键弹出菜单,选择【Clean(selection only)】菜单即可。
16、如何快速生成一个现有工程除了工程名外完全相同的新工程
在新建工程的“New”对话框中选择“Custom Appwizard”项,输入新工程的名字,单击【OK】按钮。出现“Custom AppWizard”项,输入新工程的名字,单击【OK】按钮。出现“Custom AppWizard-Step 1 of 2”对话框,选择“An existing Project”项,单击【Next】按钮。出现“Custom AppWizard-Step 2 of 2”对话框,选择现有工程的工程文件名,最后单击【Finish】按钮。编译后就生成一个与现有工程相同但可以重新取名的工程AppWizard。
现在就可以项用MFC AppWizard一样用这个定制的向导。如果不想用了,可以在Visual C++ 6.0安装目录下Common\\MSDev98\\Template目录中删除该Wizard对应的.awx和.pdb文件。
17、如何解决Visual C++ 6.0不正确连接的问题
情景:明明改动了一个文件,却要把整个项目全部重新编译链接一次。刚刚链接好,一运行,又提示重新编译链接一次。
这是因为出现了未来文件(修改时间和创建时间比系统时间晚)的缘故。可以这样处理:找到工程文件夹下的debug目录,将创建和修改时间都比系统时间的文件全部删除,然后再从新“Rebuild All”一次。
18、引起LNK2001的常见错误都有哪些
遇到的LNK2001错误主要为:unresolved external symbol “symbol”。
如果链接程序不能在所有的库和目标文件内找到所引用的函数、变量或标签,将产生此错误信息。
一般来说,发生错误的原因有两个:一是所引用的函数、变量不存在,拼写不正确或者使用错误;其次可能使用了不同版本的链接库。以下是可能产生LNK2001错误的原因:
<1>由于编码错误导致的LNK2001错误
(1)不相匹配的程序代码或模块定义(.DEF)文件导致LNK2001。例如,如果在C++源文件了
内声明了一变量“var1”,却试图在另一个文件内以变量“var1”访问改变量。
(2)如果使用的内联函数是在.cpp文件内定义的,而不是在头文件内定义将导致LNK2001错误。
(3)调用函数时如果所用的参数类型和头函数声明时的类型不符将会产生LNK2001错误。 (4)试图从基类的构造函数或析构函数中调用虚拟函数时将会导致LNK2001错误。 (5)要注意函数和变量的可公用性,只有全局变量、函数是可公用的。静态函数和静态变量具有相同的使用范围限制。当试图从文件外部方位任何没有在该文件内声明的静态变量时将导致编译错误或LNK2001错误。
<2>由于编译和联机的设置而造成的LNK2001错误
(1)如果编译时使用的是/NOD(/NODERAULTLIB)选项,程序所需要的运行库和MFC时将得到又编译器写入目标文件模块,但除非在文件中明确包含这些库名,否则这些库不会被链接进工程文件。这种情况下使用/NOD将导致LNK2001错误。
2)如果没有为wWinMainCRTStartup设定程序入口,在使用Unicode和MFC时将出现“unresolved external on _WinMain@16”的LNK2001错误信息。
(3)使用/MD选项编译时,既然所有的运行库都被保留在动态链接库之内,源文件中对“func”的引用,在目标文件里即对“__imp__func”的引用。如果试图使用静态库LIBC.LIB或LIBCMT.LIB进行链接,将在__imp__func上发生LNK2001错误。如果不使用/MD选项编译,在使用MSVCxx.LIB链接时也会发生LNK2001错误。
(4)使用/ML选项编译时,如用LIBCMT.LIB链接会在_errno上发生LNK2001错误。 (5)当编译调试版的应用程序时,如果采用发行版模态库进行链接也会产生LNK2001错误;同样,使用调试版模态库链接发行版应用程序时也会产生相同的错误。
(6)不同版本的库和编译器的混合使用也能产生问题,因为新版的库里可能包含早先的版本没有的符号和说明。
(7)在不同的模块中使用内联和非内联的编译选项能够导致LNK2001错误。如果创建C++库时打开了函数内联(/Ob1或/Ob2),但是在描述该函数的相应头文件里却关闭了函数内联(没有inline关键字),只是将得到错误信息。为避免该问题的发生,应该在相应的头文件中用inline关键字标志为内联函数。
(8)不正确的/SUBSYSTEM或ENTRY设置也能导致LNK2001错误。
19、如何调试一个没有源码的exe文件调用的dll
在Visual C++ 6.0中,进入“Project Setting”对话框然后选择Debug标签页。通常Visual Studio默认“executable for debug session”为可执行文件名,但可以将他改成任何你想要的程序。甚至可以指定不同的工作目录以及传递参数到你的程序。这个技术常用来调试Dlls、名字空间扩展、COM对象和其他从某些EXE以及从第三方的EXE中调用的plug-in程序。
20、Visual C++ 6.0工程中的项目文件都表示什么
.opt:工程关于开发环境的参数文件。如工具条位置等信息。
.aps(AppStudio File)资源辅助文件,二进制格式,一般不用去管它。
.clw:ClassWizard信息文件,实际上是INI文件格式,有兴趣可以研究一下。有时候ClassWizard出了问题,手工修改CLW文件可以解决。如果此文件不存在的话,每次用
ClassWizard的时候回提示是否重建。
.dsp(DevelopStudio Project):项目文件,文本格式,不过不熟悉的不要手工修改。 .dsw(DevelopStudio Workspace):是工作区文件,其他特点和.dsp差不多。
.plg:是编译信息文件,编译时的error和warning信息文件(实际上是一个html文件),一般用处不大。在单击菜单【Tool】->【Option】弹出的对话框里面有个选项可以控制这个文件的生成。
.hpj(Help Project):是生成帮助文件的工程,用microsoft Help Compiler可以处理。 .mdp(Microsoft DevStudio Project):是旧版本的项目文件,如果要打开此文件的话,会提示你是否转换成新的.dsp格式。
.bsc:是用于浏览项目信息的,如果用Source Brower的话就必须有这个文件。如果不用这个功能的话,可以在Project Options里面去掉Generate Browse Info File,这样可以加快编译速度。
.map是执行文件的映象信息记录文件,除非对系统底层,这个文件一般用不着。 .pch(Pre-Compiled File):是与编译文件,可以加快编译速度,但是文件非常大。
.pdb(Program Database):记录了程序有关的一些数据和调试信息,在调试的时候可能有用。 .exp:只有在编译DLL的时候才会生成,记录了DLL文件的一些信息,一般也没有用。 .ncb:无编译浏览文件(no compile browser)。当自动完成功能出问题时可以删除此文件。编译工程后会自动生成。
1.4 利用MFC进行开发的通用方法介绍
以下是我在最初学习VC时所常用的开发思路和方法,希望能对初学VC的朋友有所帮助和启发。
1、开发需要读写文件的应用程序并且有简单的输入和输出可以利用单文档视结构。 2、开发注重交互的简单应用程序可以使用对话框为基础的窗口,如果文件读写简单这可利用CFile进行。
3、开发注重交互并且文件读写复杂的的简单应用程序可以利用以CFormView为基础视的单文档视结构。
4、利用对话框得到用户输入的数据,在等级提高后可使用就地输入。
5、在对多文档要求不强烈时尽量避免多文档视结构,可以利用分隔条产生单文档多视结构。 6、在要求在多个文档间传递数据时使用多文档视结构。
7、学会利用子窗口,并在自定义的子窗口包含多个控件达到封装功能的目的。 8、尽量避免使用多文档多视结构。
9、不要使用多重继承并尽量减少一个类中封装过多的功能。
1.5 MFC中常用类,宏,函数介绍
常用类
CRect:用来表示矩形的类,拥有四个成员变量:top left bottom right。分别表是左上角和右下角的坐标。可以通过以下的方法构造:
CRect( int l, int t, int r, int b ); 指明四个坐标 CRect( const RECT& srcRect ); 由RECT结构构造 CRect( LPCRECT lpSrcRect ); 由RECT结构构造
CRect( POINT point, SIZE size ); 有左上角坐标和尺寸构造 CRect( POINT topLeft, POINT bottomRight ); 有两点坐标构造 下面介绍几个成员函数: int Width( ) const; 得到宽度 int Height( ) const; 得到高度 CSize Size( ) const; 得到尺寸
CPoint& TopLeft( ); 得到左上角坐标 CPoint& BottomRight( ); 得到右下角坐标 CPoint CenterPoint( ) const; 得当中心坐标
此外矩形可以和点(CPoint)相加进行位移,和另一个矩形相加得到“并”操作后的矩形。 CPoint:用来表示一个点的坐标,有两个成员变量:x y。 可以和另一个点相加。 CString:用来表示可变长度的字符串。使用CString可不指明内存大小,CString会根据需要自行分配。下面介绍几个成员函数: GetLength 得到字符串长度 GetAt 得到指定位置处的字符 operator + 相当于strcat
void Format( LPCTSTR lpszFormat, ... ); 相当于sprintf Find 查找指定字符,字符串 Compare 比较
CompareNoCase 不区分大小写比较 MakeUpper 改为小写 MakeLower 改为大写
CStringArray:用来表示可变长度的字符串数组。数组中每一个元素为CString对象的实例。下面介绍几个成员函数: Add 增加CString
RemoveAt 删除指定位置CString对象 RemoveAll 删除数组中所有CString对象 GetAt 得到指定位置的CString对象 SetAt 修改指定位置的CString对象 InsertAt 在某一位置插入CString对象 常用宏 RGB TRACE ASSERT VERIFY
常用函数
CWindApp* AfxGetApp();
HINSTANCE AfxGetInstanceHandle( ); HINSTANCE AfxGetResourceHandle( );
int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );用于弹出一个消息框
C/C++——小编谈C语言函数那些事(53)
C程序是由一组或是变量或是函数的外部对象组成的。 函数是一个自我包含的完成一定相关功能的执行代码段。下面小编和大家分享下C语言中的函数。
1. div函数
div函数的功能是将两个整数相除, 返回商和余数,其用法为:div_t (int number, int denom);程序实例如下: #include
div_t x; int main(void) {
x = div(10,3);
printf(\ return 0; }
2. dup函数
dup函数的功能是复制一个文件句柄,其用法为int dup(int handle);程序实例代码如下:
#include
void flush(FILE *stream); int main(void) {
FILE *fp;
char msg[] = \ fp = fopen(\ fwrite(msg, strlen(msg), 1, fp); clrscr();
printf(\ DUMMY.FIL:\ getch(); flush(fp);
printf(\ key to quit:\ getch(); return 0; }
void flush(FILE *stream) {
int duphandle; fflush(stream);
duphandle = dup(fileno(stream)); DOS buffer */ close(duphandle); }
3. atan2函数
atan2函数的功能是计算Y/X的反正切值, 其用法为double atan2(double y, double x);程序实例代码如下: #include
double result;
double x = 90.0, y = 45.0; result = atan2(y, x);
printf(\ return 0; }
4. gety函数
gety函数的功能是返回当前图形位置的y坐标,其用法为:int far gety(void);程序实例代码如下: #include
{
int gdriver = DETECT, gmode, errorcode; char msg[80];
initgraph(&gdriver, &gmode, \ errorcode = graphresult(); if (errorcode != grOk) {
printf(\ printf(\ getch(); exit(1); }
moveto(getmaxx() / 2, getmaxy() / 2);
sprintf(msg, \ outtext(msg); getch(); closegraph(); return 0; }
2.1 和GUI有关的各种对象
在Windows中有各种GUI对象(不要和C++对象混淆),当你在进行绘图就需要利用这些对
象。而各种对象都拥有各种属性,下面分别讲述各种GUI对象和拥有的属性。 字体对象CFont用于输出文字时选用不同风格和大小的字体。可选择的风格包括:是否为斜体,是否为粗体,字体名称,是否有下划线等。颜色和背景色不属于字体的属性。关于如何创建和使用字体在2.2 在窗口中输出文字中会详细讲解。刷子CBrush对象决定填充区域时所采用的颜色或模板。对于一个固定色的刷子来讲它的属性为颜色,是否采用网格和网格的类型如水平的,垂直的,交叉的等。你也可以利用8*8的位图来创建一个自定义模板的刷子,在使用这种刷子填充时系统会利用位图逐步填充区域。关于如何创建和使用刷子在2.3 使用刷子,笔进行绘图中会详细讲解。画笔CPen对象在画点和画线时有用。它的属性包括颜色,宽度,线的风格,如虚线,实线,点划线等。关于如何创建和使用画笔在2.3 使用刷子,笔进行绘图中会详细讲解。位图CBitmap对象可以包含一幅图像,可以保存在资源中。
关于如何使用位图在2.4 在窗口中绘制设备相关位图,图标,设备无关位图中会详细讲解。还有一种特殊的GUI对象是多边形,利用多边形可以很好的限制作图区域或是改变窗口外型。关于如何创建和使用多边形在2.6 多边形和剪贴区域中会详细讲解。在Windows中使用GUI对象必须遵守一定的规则。首先需要创建一个合法的对象,不同的对象创建方法不同。然后需要将该GUI对象选入DC中,同时保存DC中原来的GUI对象。如果选入一个非法的对象将会引起异常。在使用完后应该恢复原来的对象,这一点特别重要,如果保存一个临时对象在DC中,而在临时对象被销毁后可能引起异常。有一点必须注意,每一个对象在重新创建前必须销毁,下面的代码演示了这一种安全的使用方法:
OnDraw(CDC* pDC) { CPen pen1,pen2; pen1.CreatePen(PS_SOLID,2,RGB(128,128,128));//创建对象 pen2.CreatePen(PS_SOLID,2,RGB(128,128,0));//创建对象 CPen* pPenOld=(CPen*)pDC->SelectObject(&pen1);//选择对象进DC drawWithPen1... (CPen*)pDC->SelectObject(&pen2);//选择对象进DC drawWithPen2... pen1.DeleteObject();//再次创建前先销毁 pen1.CreatePen(PS_SOLID,2,RGB(0,0,0));//再次创建对象 (CPen*)pDC->SelectObject(&pen1);//选择对象进DC drawWithPen1... pDC->SelectObject(pOldPen);//恢复 }
此外系统中还拥有一些库存GUI对象,你可以利用
CDC::SelectStockObject(SelectStockObject( int nIndex )选入这些对象,它们包括一些固定颜色的刷子,画笔和一些基本字体。
? ? ? ? ? ? ? ?
BLACK_BRUSH Black brush. DKGRAY_BRUSH Dark gray brush. GRAY_BRUSH Gray brush. HOLLOW_BRUSH Hollow brush. LTGRAY_BRUSH Light gray brush. NULL_BRUSH Null brush. WHITE_BRUSH White brush. BLACK_PEN Black pen.
? ? ? ? ? ? ?
NULL_PEN Null pen. WHITE_PEN White pen.
ANSI_FIXED_FONT ANSI fixed system font. ANSI_VAR_FONT ANSI variable system font. DEVICE_DEFAULT_FONT Device-dependent font. OEM_FIXED_FONT OEM-dependent fixed font.
SYSTEM_FONT The system font. By default, Windows uses the system font to draw menus, dialog-box controls, and other text. In Windows versions 3.0 and later, the system font is proportional width; earlier versions of Windows use a fixed-width system font.
? SYSTEM_FIXED_FONT The fixed-width system font used in Windows prior to version 3.0. This object is available for compatibility with earlier versions of Windows.
? DEFAULT_PALETTE Default color palette. This palette consists of the 20 static colors in the system palette.
这些对象留在DC中是安全的,所以你可以利用选入库存对象来作为恢复DC中GUI对象。 大家可能都注意到了绘图时都需要一个DC对象,DC(Device Context设备环境)对象是一个抽象的作图环境,可能是对应屏幕,也可能是对应打印机或其它。这个环境是设备无关的,所以你在对不同的设备输出时只需要使用不同的设备环境就行了,而作图方式可以完全不变。这也就是Windows耀眼的一点设备无关性。如同你将对一幅画使用照相机或复印机将会产生不同的输出,而不需要对画进行任何调整。DC的使用会穿插在本章中进行介绍。
c++继承经典例子 #include
class Base {
private:
int b_number; public:
Base( ){}
Base(int i) : b_number (i) { } int get_number( ) {return b_number;}
void print( ) {cout << b_number << endl;} };
class Derived : public Base {
private:
int d_number; public:
// constructor, initializer used to initialize the base part of a Derived object. Derived( int i, int j ) : Base(i), d_number(j) { };
// a new member function that overrides the print( ) function in Base void print( ) {
cout << get_number( ) << \ // access number through get_number( ) cout << d_number << endl; } };
int main( ) {
Base a(2);
Derived b(3, 4);
cout << \
a.print( ); // print( ) in Base cout << \
b.print( ); // print( ) in Derived cout << \
b.Base::print( ); // print( ) in Base
return 0; }
--------------------------------------------------------------------------------
没有虚析构函数,继承类没有析构
//Example: non- virtual destructors for dynamically allocated objects. #include
class Thing { public:
virtual void what_Am_I( ) {cout << \
~Thing(){cout<<\};
class Animal : public Thing { public:
virtual void what_Am_I( ) {cout << \~Animal(){cout<<\};
void main( ) {
Thing *t =new Thing; Animal*x = new Animal; Thing* array[2];
array[0] = t; // base pointer array[1] = x;
for (int i=0; i<2; i++) array->what_Am_I( ) ;
delete array[0]; delete array[1]; return ; }
--------------------------------------------------------------------------------
纯虚函数,多态 #include
class Point {
private:
double x; double y; public:
Point(double i, double j) : x(i), y(j) { } void print( ) const
{ cout << \};
class Figure
{
private:
Point center; public:
Figure (double i = 0, double j = 0) : center(i, j) { } Point& location( ) {
return center;
} // return an lvalue void move(Point p) {
center = p; draw( ); }
virtual void draw( ) = 0; // draw the figure virtual void rotate(double) = 0; // rotate the figure by an angle };
class Circle : public Figure {
private:
double radius; public:
Circle(double i = 0, double j = 0, double r = 0) : Figure(i, j), radius(r) { } void draw( ) {
cout << \ circle with center \ location( ).print( );
cout << \ }
void rotate(double) {
cout << \ } // must be defined };
class Square : public Figure
{
private:
double side; // length of the side
double angle; // the angle between a side and the x-axis
public:
Square(double i = 0, double j = 0, double d = 0, double a = 0) : Figure(i, j), side(d), angle(a) { } void draw( ) {
cout << \ square with center \ location( ).print( );
cout << \
<< \ }
void rotate(double a) {
angle += a;
cout << \ }
void vertices( ) {
cout << \ // calculate coordinates of the vertices of the square } };
int main( ) {
Circle c(1, 2, 3); Square s(4, 5, 6); Figure *f = &c, &g = s;
f -> draw( );
f -> move(Point(2, 2));
g.draw( ); g.rotate(1); s.vertices( );
// Cannot use g here since vertices( ) is not a member of Figure.
return 0; }
//////////////////////////////////////////////////////////////////// #include
class Thing
{ public:
virtual void what_Am_I( ) {cout << \
~Thing(){cout<<\};
class Animal : public Thing {
public:
virtual void what_Am_I( ) {cout << \
~Animal(){cout<<\};
void main( ) {
Thing t ; Animal x ; Thing* array[2];
array[0] = &t; // base pointer array[1] = &x;
for (int i=0; i<2; i++) array->what_Am_I( ) ;
return ; }
--------------------------------------------------------------------------------
多继承
#include
private: int a; public:
A(int i) : a(i) { }
virtual void print( ) {cout << a << endl;} int get_a( ) {return a;}
};
class B {
private: int b; public:
B(int j) : b(j) { }
void print( ) {cout << b << endl;} int get_b( ) {return b;} };
class C : public A, public B {
int c; public:
C(int i, int j, int k) : A(i), B(j), c(k) { }
void print( ) {A::print( ); B::print( );} // use print( ) with scope resolution
void get_ab( ) {cout << get_a( ) << \ // use get_a( ) and get_b( ) without scope resolution };
int main( ) {
C x(5, 8, 10); A* ap = &x;
B* bp = &x;
ap -> print( ); // use C::print( );
bp -> print( ); // use B::print( );
// bp -> A::print( ); // as if x is inherited from B only, // cannot access A::print( ); x.A::print( ); // use A::print( ); x.get_ab( );
return 0; }
--------------------------------------------------------------------------------
共同基类的多继承
#include
class R {int r; public:
R(int anInt){ r = anInt;};
printOn(){ cout<<\
class A : public R { int a;
public:
A(int int1,int int2):R(int2){ a = int1;};};
class B : public R { int b;
public:
B(int int1,int int2):R(int2){ b = int1;};};
class C : public A, public B {
int c; public:
C(int int1,int int2, int int3):A(int2,int3), B(int2,int3){ c = int1;} };
int main( ) { int i;
R rr(10); A aa(20,30); B bb (40,50);
C cc(5, 7, 9);
rr.printOn();
aa.printOn(); //inherits R printOn bb.printOn(); //inherits R printOn //cc.printOn(); //would give error return 0;}
--------------------------------------------------------------------------------
虚基类
#include
class R { int r; public:
R (int x = 0) : r(x) { } // constructor in R void f( ){ cout<<\ void printOn(){cout<<\};
class A : public virtual R { int a;
public:
A (int x, int y) : R(x), a(y) { } // constructor in A void f( ){ cout<<\};
class B : public virtual R {int b; public:
B(int x, int z) : R(x), b(z) { }// constructor in B void f( ){ cout<<\};
class C : public A, public B { int c; public:
// constructor in C, which constructs an R object first
C(int x, int y, int z, int w) : R(x), A(x, y), B(x, z), c(w) { }
void f( ){ cout<<\};
void main() { R rr(1000);
A aa(2222,444); B bb(3333,111);
C cc(1212,345,123,45);
cc.printOn(); //uses R printOn but only 1 R..no ambiguity cc.f(); // shows multiple call of the R::f() }
////////////////////////////////////////
#include
class R { int r; public:
R (int x = 0) : r(x) { } // constructor in R void f( ){ cout<<\};
class A : virtual public R { int a ;
protected:
void fA( ){cout<<\
public:
A (int x, int y) : R(x), a(y) { } // constructor in A void f( ) {fA( ); R::f( );} };
class B : virtual public R
{ int b; protected:
void fB( ){cout<<\public:
B (int x, int y) : R(x), b(y) { } // constructor in A void f( ) {fB( ); R::f( );} };
class C : public A, public B { int c;
protected:
void fC( ){ cout<<\ public:
C(int x, int y, int z, int w) : R(x), A(x, y), B(x, z), c(w) { }
void f( ) {
R::f( ); // acts on R stuff only A::fA( ); //acts on A stuff only
B::fB( ); // acts on B stuff only fC( ); // acts on C stuff only
} };
void main() { R rr(1000); A aa(2222,444); B bb(3333,111); C cc(1212,345,123,45); cc.f(); }
--------------------------------------------------------------------------------
私有继承
// Access levels
#include
class Base {
private:
int priv;
protected:
int prot;
int get_priv( ) {return priv;} public:
int publ;
Base( );
Base(int a, int b, int c) : priv(a), prot(b), publ(c) { } int get_prot( ) {return prot;} int get_publ( ) {return publ;} };
class Derived1 : private Base // private inheritance { public:
Derived1 (int a, int b, int c) : Base(a, b, c) { } int get1_priv( ) {return get_priv( );} // priv not accessible directly
int get1_prot( ) {return prot;} int get1_publ( ) {return publ;} };
class Leaf1 : public Derived1 { public:
Leaf1(int a, int b, int c) : Derived1(a, b, c) { } void print( ) {
cout << \// << get_priv( ) // not accessible << get1_prot( ) << \
// << get_prot( ) // not accessible // << publ // not accessible << get1_publ( ) << endl;
} // data members not accessible. get_ functions in Base not accessible };
class Derived2 : protected Base // protected inheritance {
public:
Derived2 (int a, int b, int c) : Base(a, b, c) { } };
class Leaf2 : public Derived2 {
public:
Leaf2(int a, int b, int c) : Derived2(a, b, c) { } void print( )
{
cout << \// << priv // not accessible << prot << \
<< publ << endl;
} // public and protected data members accessible. get_ functions in Base accessible. };
class Derived3 : public Base // public inheritance { public:
Derived3 (int a, int b, int c) : Base(a, b, c) { } };
class Leaf3 : public Derived3
{
public:
Leaf3(int a, int b, int c) : Derived3(a, b, c) { } void print( ) {
cout << \ << prot << \ << publ << endl;
} // public and protected data members accessible. get_ functions in Base accessible };
int main( )
{
Derived1 d1(1, 2, 3); Derived2 d2(4, 5, 6); Derived3 d3(7, 8, 9);
// cout << d1.publ; // not accessible // cout << d1.get_priv( ); // not accessible // cout << d2.publ; // not accessible // cout << d2.get_priv( ); // not accessible cout << d3.publ; // OK cout << d3.get_prot( ); // OK
Leaf1 lf1(1, 2, 3); Leaf2 lf2(4, 5, 6); Leaf3 lf3(7, 8, 9);
// cout << lf1.publ << endl; // not accessible // cout << lf2.publ << endl; // not accessible cout << lf3.publ << endl; // OK
return 0; }
--------------------------------------------------------------------------------
多级继承
// Point-Circle-Cylinder #include
// THE POINT CLASS
class Point {
friend ostream & operator<<(ostream &,Point &);
public: // constructor
Point (double xval =0, double yval=0 ) { x=xval; y=yval;};
protected: // accessed by derived class double x; double y;
};
ostream & operator << (ostream & os,
Point & apoint) {
cout <<\
<< apoint.y<< \ return os; }
//The Circle class inherits from class Point
class Circle : public Point {
friend ostream & operator<<(ostream &,Circle&);
public:
Circle (double r=0,double xval=0,double yval=0)
:Point(xval,yval), radius(r) { //radius = r; }
double area() {
return (3.14159* radius *radius); }
protected: double radius; };
//note casting circle to point
ostream & operator <<(ostream & os, Circle & aCircle) {
cout<< \os<< aCircle.x << \ os<< aCircle.y << \ return os; }
// THE CYLINDER CLASS class Cylinder : public Circle
{
friend ostream & operator << (ostream & ,Cylinder &); public:
Cylinder (double hv=0,double rv=0,
double xv=0,double yv=0 ) : Circle( xv,yv,rv) {
height = hv; }
double area ( );
protected: // may have derived classes double height; };
double Cylinder :: area ( )
{ // Note that cylinder area uses Circle area
return 2.0* Circle::area() + 2.0*3.14159* radius*height; }
ostream & operator << (ostream & os,
Cylinder & acylinder)
{
cout << \ cout << \
cout << \ y: \
cout << \ radius: \ cout << \ height: \ << endl; return os; }
int main(void) {
Point p(2,3);
Circle c(7,6,5);
Cylinder cyl(10,11,12,13); cout << p;
cout << c;
cout << \
cout<< cyl;
cout<<\
cout<<\
<< cyl.Circle::area() << endl;
return 0; }
--------------------------------------------------------------------------------
protected 访问控制属性在继承的意义
//Example of treating derived class object as base class objects. Point------Circle
#include
// THE POINT CLASS
class Point {
friend ostream & operator<<(ostream &,Circle&); public:
Point (double xval =0, double yval=0 ) { x=xval; y=yval;};
public:
void print()
{
cout <<\}
protected: // accessed by derived class double x; double y; };
ostream & operator << (ostream & os, Point & apoint) {
cout <<\ return os; }
//The Circle class inherits from class Point class Circle : public Point {
friend ostream & operator<<(ostream &,Circle&);
public:
Circle (double r=0,double xval=0,double yval=0):Point(xval,yval) { radius = r;};
void print()
{
cout<< \cout <<\}
double area()
{ return (3.14159* radius *radius);};
protected: double radius; };
//note casting circle to point
ostream & operator <<(ostream & os, Circle & aCircle) {
cout<< \cout<< (Point) aCircle << \
return os;
}
//We will look at a few main programs based on previous class definitions. Casting and assignments
void main (void ) {
Point p(2,3); cout <<\ \
Point pp(0,0); cout <<\ \
Circle c(7,6,5); cout <<\ \ //radius =7
pp = p; cout <<\ \ //built in assign =
// a circle is a member of the point class so assign a circle to a point.
pp = c; //legal; also assignment O.K. cout <<\ \
pp= (Point) c; // but better use the cast
cout <<\ \ //note we get only the point part of the Circle
//c = (Circle) pp; // illegal Cannot convert 'class Point' to 'class Circle'
//c=pp; //illegal assignment not defined
Point* p; p = &c;
P->print(); //call base class print ((Circle*)p)->print();
Point& r = c; r.print();
((Circle&)r).print(); }
--------------------------------------------------------------------------------
类的兼容性规则
#include
class Base { public:
void func( )
{cout << \ };
class Derived : public Base {
public:
void func( )
{cout << \};
void foo(Base b) { b.func( ); }
int main( ) {
Derived d; Base b; Base * p = &d; Base& br = d;
b = d; b.func( ); d.func( ); p -> func( ); foo(d); br.func( );
return 0; }
--------------------------------------------------------------------------------
虚析构函数,防止内存泄露 #include
#include
class Base {
protected: int id; char * name; public:
// default constructor
Base(int a = 0, char * s = \ {
if (!s) {
name = NULL; }
else
{
name = new char[strlen(s) + 1]; strcpy(name, s); }
cout << \ }
// copy constructor Base(const Base& b) : id(b.id) {
if (!b.name) { name = NULL; } else
{
name = new char[strlen(b.name) + 1]; strcpy(name, b.name);
}
cout << \ }
// destructor ~Base( ) {
if( name != NULL ) delete [ ] name; cout << \ }
const Base& operator= (const Base& b); friend ostream& operator << (ostream&, const Base&); };
const Base& Base:perator= (const Base& b)
{
if (this != &b) // Check if an object is assigned to itself. {
id = b.id;
delete [ ] name; // Destroy the old object. if (!b.name) { name = NULL; } else
{
name = new char[strlen(b.name) + 1]; strcpy(name, b.name); } }
cout << \ return *this; }
ostream& operator << (ostream& out, const Base& b) {
out << \ out << \
return out; }
class Derived : public Base {
private:
float f;
char * label; public:
// default constructor
Derived(int a = 0, char * s = \ {
if (!t) { label = NULL; } else {
label = new char [strlen(t) + 1]; strcpy(label, t); }
cout << \ }
// copy constructor
Derived(const Derived& d) : Base(d), f(d.f) // d used as an instance of Base
{
if(!d.label) { label = NULL; } else {
label = new char [strlen(d.label) + 1]; strcpy(label, d.label); }
cout << \ }
// destructor
~Derived( ) {
delete [ ] label;
cout << \ }
const Derived& operator= (const Derived& d); friend ostream& operator << (ostream&, const Derived&); };
const Derived& Derived:perator= (const Derived& d) {
if (this != &d) {
delete [ ] label;
Base:perator=(d); // Assign the Base part of d to the Base // part of the object that calls this operator; f = d.f;
if (!d.label) { label = NULL; } else {
label = new char [strlen(d.label) + 1]; strcpy(label, d.label);
}
cout << \ }
return *this; }
ostream& operator << (ostream& out, const Derived& d) {
out << (Base)d; // Convert d to Base object to output Base members. out << \
out << \ return out;
}
int main( ) {
Derived d1; Derived d2(d1);
return 0; }
本文来自CSDN博客,转载http://blog.csdn.net/zhaori/archive/2007/07/20/1700356.aspx
请标出处明: