Visual C++ 2008入门经典 第九章类的继承和虚函数(二)

本文探讨了C++中的虚析构函数的重要性及其在派生类中的作用,同时介绍了C++/CLI环境下接口的定义及实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

////////////////////////////////////////////////////////////////////////////////
//9.6.7 虚析构函数
/*#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
const double PI = 3.14159265;
//定义纯虚函数
class CContainer
{
public:
	virtual double Volume() const = 0;
	//定义虚函数Volume()的语句通过在函数头中添加等号和0,将该函数定义成没有任何内容,这样的函数被称为纯虚函数

	virtual void ShowVolume() const
	{
	   cout<<endl
		   <<"Volume is"<<Volume()<<endl;
	}
	virtual ~CContainer(){
	   cout<<"CContainer 析构函数执行....."<<endl;
	}
	//一个问题:可以将构造函数声明为virtual吗?答案是不行的,只有析构孙函数和其它成员函数才可以
	//当使用继承时,总是照例将基类的析构函数声明为虚函数是个好主意,
	//在为析构函数的执行过程中有少量的系统开稍,但大多数情况下不用理会这一点,使用虚析构函数能够确保正确的销毁对像,
	//还能避免相反情形下可能出现的程序崩溃风险
};
class CBox : public CContainer
{
public:
	virtual void ShowVolume() const
	{
	     cout<<endl
			 <<"CBox usable volume is "<<Volume();
	}

	virtual double Volume() const
	{
	     return m_Width * m_Height * m_Length;
	}

	CBox(double lv=1.0, double wv=1.0, double hv=1.0):m_Length(lv), m_Width(wv), m_Height(hv)
	{
	}
	~CBox(){
	    cout<<"CBox析构函数执行......"<<endl;
	}
protected:
	double m_Width;
	double m_Height;
	double m_Length;
};


class CGlassBox : public CBox
{
public:
	virtual double Volume() const
	{
	     return 0.85 * m_Width * m_Height * m_Length;
	}

	CGlassBox(double lv, double wv, double hv):CBox(lv, wv, hv)
	{
	}
	~CGlassBox()
	{
	     cout<<"CGlassBox析构函数执行......"<<endl;
	}
private:
};


//CCan类-它表示啤酒或可乐罐
//ectern const double PI;
class CCan: public CContainer
{
public:
	virtual double Volume() const
	{
	     return 0.25*PI*m_Diameter*m_Height;
	}
	CCan(double hv=4.0, double dv=2.0):m_Height(hv), m_Diameter(dv)
	{
	}
	~CCan()
	{
	    cout<<"CCan析构函数执行......"<<endl;
	}
private:
	double m_Height;
	double m_Diameter;
};


int main(array<System::String ^> ^args)
{
	CContainer* pC1 = new CBox(2.0,3.0, 4.0);
	
	CCan myCan(6.5, 3.0);
	CGlassBox myGlassBox(2.0, 3.0, 4.0);
	
	pC1->ShowVolume();
	cout<<endl<<" delete CBox"<<endl;
	delete pC1; //CBox


	pC1 = new CGlassBox(4.0, 5.0, 6.0);
	pC1->ShowVolume();
	cout<<endl<<" delete CGlassBox"<<endl;
	delete pC1;
	//录我们删除pC1指向的CBox对像时,基类CCOntainer的析构函数被调用,但却没有调用CBox类的析构函数
	//同样,当我们删除添加的CGlassBox对像时,还是基类CCOntainer的析构函数被调用
	//这里跟书上的实例不太一样,析构函数的用情况是正确遥,都是先调类的析构函数,再调用基类的析构函数,对于在声明中创建的第一个人CGalssBox对像来说,被调用的析构函数有三个
	//首先是派生类的析构函数,然后是直接基类的析构函数,最后是间接的基类的析构函数

	pC1 = &myCan;
	pC1->ShowVolume();

	pC1 = &myGlassBox;
	pC1->ShowVolume();
	//delete pC1; //这里为什么最后不delete pC1了
	//是因为程序一运行结束,动态内存也就自动释放了吗???
	//delete pC1;
	cout<<endl;
	
	
	//由于派生类对像是动态创建的,因此我们不需要它们时必须使用delete运算符清理自由存储器
	system("pause");
    return 0;
}
*/

//9.7 类类之间的强制转换
//dynamic_cast运算行就是专门执行此类操作的
/*#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
const double PI = 3.14159265;
//定义纯虚函数
class CContainer
{
public:
	virtual double Volume() const = 0;
	//定义虚函数Volume()的语句通过在函数头中添加等号和0,将该函数定义成没有任何内容,这样的函数被称为纯虚函数

	virtual void ShowVolume() const
	{
	   cout<<endl
		   <<"Volume is"<<Volume()<<endl;
	}
	virtual ~CContainer(){
	   cout<<"CContainer 析构函数执行....."<<endl;
	}
	//一个问题:可以将构造函数声明为virtual吗?答案是不行的,只有析构孙函数和其它成员函数才可以
	//当使用继承时,总是照例将基类的析构函数声明为虚函数是个好主意,
	//在为析构函数的执行过程中有少量的系统开稍,但大多数情况下不用理会这一点,使用虚析构函数能够确保正确的销毁对像,
	//还能避免相反情形下可能出现的程序崩溃风险
};
class CBox : public CContainer
{
public:
	virtual void ShowVolume() const
	{
	     cout<<endl
			 <<"CBox usable volume is "<<Volume();
	}

	virtual double Volume() const
	{
	     return m_Width * m_Height * m_Length;
	}

	CBox(double lv=1.0, double wv=1.0, double hv=1.0):m_Length(lv), m_Width(wv), m_Height(hv)
	{
	}
	~CBox(){
	    cout<<"CBox析构函数执行......"<<endl;
	}
protected:
	double m_Width;
	double m_Height;
	double m_Length;
};


class CGlassBox : public CBox
{
public:
	virtual double Volume() const
	{
	     return 0.85 * m_Width * m_Height * m_Length;
	}

	CGlassBox(double lv, double wv, double hv):CBox(lv, wv, hv)
	{
	}
	~CGlassBox()
	{
	     cout<<"CGlassBox析构函数执行......"<<endl;
	}
private:
};


//CCan类-它表示啤酒或可乐罐
//ectern const double PI;
class CCan: public CContainer
{
public:
	virtual double Volume() const
	{
	     return 0.25*PI*m_Diameter*m_Height;
	}
	CCan(double hv=4.0, double dv=2.0):m_Height(hv), m_Diameter(dv)
	{
	}
	~CCan()
	{
	    cout<<"CCan析构函数执行......"<<endl;
	}
private:
	double m_Height;
	double m_Diameter;
};


int main(array<System::String ^> ^args)
{
	//
	CContainer* pContainer = new CGlassBox(2.0, 3.0, 4.0); //定义一个基类指针
	pContainer->ShowVolume();
	
	CBox* pBox = dynamic_cast<CBox*>(pContainer); //将基类指针强制转换为类层次结构中的CBox*类型
	pBox->ShowVolume();

	CGlassBox* pGlassBox = dynamic_cast<CGlassBox*>(pContainer);
	//转换为实际的类型CGlassBox*
	pGlassBox->ShowVolume();	
	
	//由于派生类对像是动态创建的,因此我们不需要它们时必须使用delete运算符清理自由存储器
	system("pause");
    return 0;
}*/


//9.8 嵌套类
//嵌套类可以自由访问封装类的所有静态成员,通过封装类的对像或指向封装类对像的指针或引用,还可以访问所有实例成员
//封装类只能访问嵌套类的公有成员,但在封类所有私有的嵌套类中,类成员通常被声明为public,以使封装类的函数能够自由访问整个嵌套类
/*
#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
const double PI = 3.14159265;
//定义纯虚函数
class CContainer
{
public:
	virtual double Volume() const = 0;
	//定义虚函数Volume()的语句通过在函数头中添加等号和0,将该函数定义成没有任何内容,这样的函数被称为纯虚函数

	virtual void ShowVolume() const
	{
	   cout<<endl
		   <<"Volume is"<<Volume()<<endl;
	}
	virtual ~CContainer(){
	   cout<<"CContainer 析构函数执行....."<<endl;
	}
	//一个问题:可以将构造函数声明为virtual吗?答案是不行的,只有析构孙函数和其它成员函数才可以
	//当使用继承时,总是照例将基类的析构函数声明为虚函数是个好主意,
	//在为析构函数的执行过程中有少量的系统开稍,但大多数情况下不用理会这一点,使用虚析构函数能够确保正确的销毁对像,
	//还能避免相反情形下可能出现的程序崩溃风险
};
class CBox : public CContainer
{
public:
	virtual void ShowVolume() const
	{
	     cout<<endl
			 <<"CBox usable volume is "<<Volume();
	}

	virtual double Volume() const
	{
	     return m_Width * m_Height * m_Length;
	}

	CBox(double lv=1.0, double wv=1.0, double hv=1.0):m_Length(lv), m_Width(wv), m_Height(hv)
	{
	}
	~CBox(){
	    cout<<"CBox析构函数执行......"<<endl;
	}
protected:
	double m_Width;
	double m_Height;
	double m_Length;
};


class CGlassBox : public CBox
{
public:
	virtual double Volume() const
	{
	     return 0.85 * m_Width * m_Height * m_Length;
	}

	CGlassBox(double lv, double wv, double hv):CBox(lv, wv, hv)
	{
	}
	~CGlassBox()
	{
	     cout<<"CGlassBox析构函数执行......"<<endl;
	}
private:
};


//CCan类-它表示啤酒或可乐罐
//ectern const double PI;
class CCan: public CContainer
{
public:
	virtual double Volume() const
	{
	     return 0.25*PI*m_Diameter*m_Height;
	}
	CCan(double hv=4.0, double dv=2.0):m_Height(hv), m_Diameter(dv)
	{
	}
	~CCan()
	{
	    cout<<"CCan析构函数执行......"<<endl;
	}
private:
	double m_Height;
	double m_Diameter;
};


class CStack
{
private:
	struct CItem
	{
	    CBox* pBox;   //一个pBox指针
		CItem* pNext; //一个CItem的指针,该指针的一下个指针

		CItem(CBox* pB, CItem* pN):pBox(pB), pNext(pN)
		{
		}
	};

	CItem* pTop; //定义头指针
public:
	void Push(CBox* pBox)
	{    //生成一个CItem对像,传入pBox与当前的pTop指针,也就是当前的pTop指针为新的pTop指针的一下个指针
	     pTop = new CItem(pBox, pTop);
	}

	CBox* Pop()
	{
		if(pTop == 0){
		    return 0;
		}

		CBox* pBox = pTop->pBox;   //取得当前头指针所指向的pBox对像,放入到pBox中去
		CItem * pTemp = pTop;      //将当前的头指针记录下来,放到pTemp中
		pTop = pTop->pNext;        //将头指针向下移动一位
		delete pTemp;              //删除记录的老的头指针
		return pBox;               //返回pBox对像
	}


};

int main(array<System::String ^> ^args)
{
	CBox* pBoxes[] = { new CBox(2.0, 3.0, 4.0),
	                   new CGlassBox(2.0,3.0,4.0),
	                   new CBox(4.0,5.0,6.0),
	                   new CGlassBox(4.0,5.0,6.0)};

	for(int i=0; i<4; i++){
	     pBoxes[i]->ShowVolume();
	}
	cout<<endl<<"现在开始将四个对像全部装入Stack中"<<endl;
	CStack* pStack = new CStack;
	for(int i=0; i<4; i++){
	    pStack->Push(pBoxes[i]);
	}

	cout<<"现在开始读取Stack中的数据"<<endl;
	for(int i=0; i<4; i++){
	    pStack->Pop()->ShowVolume();
	}
	//使用嵌套的Struct来定义堆栈中存储的对像,CStack类的确实现了一个堆栈


	system("pause");
    return 0;
}*/


//9.9 C++/CLI编程
//包括用户定义的类在内的所有C++/CLI类,默认情况下都是派生类,因此数值和引用类都是以System::Object这个标准作为基类的
//因为System::Object是所有C++/CLI类的基类,所以句柄类型system::Object^起到了与本地C++中可用来引用任何类型的对像的void*类型相同的作用

//9.9.1 装箱与拆箱
//供所有数值类型使用的System::Object基类还负责实现基本类型数值的装箱(boxing)和拆箱(unboxing)操作
//装箱是将它转换为垃圾回收堆上的一个对像,因此它会与基类数值一起承载完整的类型信息
//拆箱是装箱的逆向操作
//double value = 3.14159265;
//Object^ boxedValue = value;
//第二个语句强制装箱value,装箱后的表示由句柄boxedValue引用
//long^ number = gcnew(999999L);
//我们可以用解引用运算符对数值类型执行拆箱操作
//Console::WriteLine(*number);
/*#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
int main(array<System::String ^> ^args)
{
    double value = 3.14159265;
    Object^ boxedValue = value;
	Console::WriteLine(boxedValue);
	system("pause");
    return 0;
}
*/

//9.9.2 C++/CLI类的继承
//String^ ToString(); 
//返回对像的String表示法,System::Object类中的实现返回字符串形式的类名,我们通常要在自己的类中重新该函数,以返回对像值的字符串表示

//bool Equals(Object^ obj)
//比较当前对像与obj,如果二者相等则返回true,否则返回false,这里的"相等"意味着引用相等性
//即两个对像是同一个,我们通常要在自己的类中重写该函数,以便宜当前对像与实参的值相等时,即二者的字符相等时返回true

//int GetHashCode()
//返回当前对像的散列码一个整数,在存储(key, object)对的集合中,散列码用于存储对象的键码,随后
//我们通过提供某个对像被存储时使用的键码,就可以从这样的集合中将该对像检索出来
/*#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;
//abstrcat定义抽像类
ref class Container abstract
{
public:
	virtual double Volume() abstract;
	//类名后面的abstract关键字,如果某个C++/CLI类包含等价于本地C++类中纯虚函数的函数
	//那么我们必须将该类指定为abstract

	virtual void ShowVolume()
	{
		Console::WriteLine(L"Volume is {0}", Volume());
	}
};

ref class Box: Container
{
public:
	virtual void ShowVolume() override
	{
		Console::WriteLine(L"Box usable volume is {0}", Volume());
	}
	

	virtual double Volume() override
	{
	     return m_Length * m_Width * m_Height;
	}
	//Box类重写了从基类继承的Volume()函数,当需要重写基类中的某个函数,我们必须总是指定override关键字
	//如果Box类不实现Volume()函数,那么它将是一个抽像类,而为了成功编译这个类,则需要将其指定为abstruct
	Box():m_Length(1.0), m_Width(1.0), m_Height(1.0){}

	Box(double lv, double wv, double hv):m_Length(lv), m_Width(wv), m_Height(hv){}
private:
protected:
	double m_Length;
	double m_Width;
	double m_Height;
};
//引用类的基类总是公有的,默认情况下编译器认为是有public关键字的
//不能像本地C++版本中那样给形参提供默认值

ref class GlassBox: Box
{
public:
	virtual double Volume() override
	{
	     return 0.85 * m_Length * m_Width * m_Height;
	}

	GlassBox(double lv, double wv, double hv):Box(lv, wv, hv){}
};

ref class Stack
{
private:
	ref struct Item
	{
	    Object^ Obj;
		Item^ Next;

		Item(Object^ obj, Item^ next):Obj(obj), Next(next){}
	};
	Item^ Top;
public:
	void Push(Object^ obj)
	{
	     Top = gcnew Item(obj, Top);
	}

	Object^ Pop()
	{
		if(Top == nullptr){
		     return nullptr;
		}
		Object^ obj = Top->Obj;
		Top = Top->Next;
		return obj;
	}
	//需要注意的第一点是区别是函娄的形参和字段现在的都是句柄,因为我们是在处理引用类对像
	//内部的结构Item现在存储着Object^类型的句柄,这样的句柄允许在堆栈中存储任何CLR类类型的对像
	//这意味着无论是数值类还是引用类都能被压入堆栈
	//这一点对本地C++中CStack类的重大改进,我们不必担心用Pop()函数时删除Item对像的问题
};
//总结这些类同本地C++类的区别
//1 只有引用类可以是派生类
//2 派生引用类的基类始终都是public
//3 引用类中没有定义的函数是抽像函数,必须使用关键字abstract声明
//4 我们必须通过在类名后面放上abstract关键字,将包含一个或多个抽像类显式指定为抽像类
//5 不包含抽像函数类也可以被指定为abstract,这种情况下我们将不能定义该类的实例
//6 当指定某个重定基类函数的函数时,我们必须显式使用override关键字




int main(array<System::String ^> ^args)
{

	array<Box^>^ boxes = {gcnew Box(2.0, 3.0, 4.0),
	                      gcnew GlassBox(2.0,3.0,4.0),
	                      gcnew Box(5.0,6.0,7.0),
	                      gcnew GlassBox(5.0,6.0,7.0)};
	Console::WriteLine(L"开始显示boxes的值:");
	for each(Box^ box in boxes){
	     box->ShowVolume();
	}
	Console::WriteLine(L"现在开始入栈操作:");
	Stack^ stack = gcnew Stack;
	for(int i=0; i<4; i++){
	     stack->Push(boxes[i]);
	}

	cout<<"现在开始出栈操作:";
	System::Object^ item;
	while((item = stack->Pop()) != nullptr){
	     safe_cast<Container^>(item)->ShowVolume();
	}

	//重新定义stack值
	for(int i=2; i<=12; i+=2)
	{
		Console::Write(L"{0,5}", i);
		stack->Push(i);
	}
	Console::WriteLine();

	while((item=stack->Pop()) != nullptr){
		Console::Write(L"{0,5}", item);
	}
	Console::WriteLine();
	

	system("pause");
    return 0;
}
*/


//9.9.3 接口类
//接口类的定久看起来非常类似于引用类的定义,但是它是个完全不同的概念,接口类指定一级将由其它类实现的函数
//以提供标准化的,可提供某种体功能的方,数值类和引用类都可以实现接口,接口不定义任何自有的函数成员
//其指定的函数是由实现该接口的各个类来定义的
//我们可以像下面这样使上一个示例中的Box类实现System::IComparable接口
/*ref class Box : Container, IComparable
{
	//接口名是在类类名Container后面,如果没有基类,则这里单独出现接口名
	//引用类只有一个基类,但可以实现任意多的接口
	//这样的类必须定义宣称要实现的各个接口指定的每一个函数
	//
public:
	virtual int COmpareTo(Object^ obj)
	{
	      if(Volume() < safe_cast<Box^>(obj)->Volume());
			  return -1;
		  else if(Volume() > safe_cast<Box^>(obj)->Volume());
		      return 1;
		  else
			  return 0;
	}
}*/

//9.9.4 定义接口类
//我们使用关键字interface class 或者interface struct定义接口类,无论是使用interface clas还是interface struct来定义接口
//接口的所有成员默认都是公有的,我们不能将它们指定为其它类型,接口的成员可以是函数,包括运算符函数,属性,静态字段和事件
//interface class IController: ITelevison, IRecorder
//{
     //Members of IController
//}
//该接口继承了ITelevison IRecorder两个接口







//Box类必须实现IContainer接口类的两个函数成员,不然它就是一个抽像类,需要用abstract关键字来定义
//Box类中这两个孙函数那么 的定义没有附加override关键字,因为我们不是重定现有的函数,而是初次实现Volume()和ShowVolume()函数


#include "stdafx.h"
#include <iostream>
using namespace std;
using namespace System;


interface class IContainer
{
     double Volume();
	 void ShowVolume();
	 //两个函数实际上是抽像函数,因为接口永远不包括函数的定义,当然,我们可以给这两个函数添加abstruct关键字
	 //但这样做是不必要的,接口定义中的实例数可以指定为virtual和abstract但这也不是必需的

};




//C++/CLI中的接口名以I打头,这个约定
ref class Box: IContainer
{
public:
	virtual void ShowVolume()
	{
		Console::WriteLine(L"CBox usable volume is {0}", Volume());
	}

	virtual double Volume()
	{
	     return m_Length * m_Width * m_Height;
	}
	Box() : m_Length(1.0), m_Width(1.0), m_Height(1.0){}

	Box(double lv, double wv, double hv):m_Length(hv), m_Width(wv), m_Height(hv)
	{	
	}
protected:
	double m_Length;
	double m_Width;
	double m_Height;
};




//引用类的基类总是公有的,默认情况下编译器认为是有public关键字的
//不能像本地C++版本中那样给形参提供默认值

ref class GlassBox: Box
{
public:
	virtual double Volume() override
	{
	     return 0.85 * m_Length * m_Width * m_Height;
	}

	GlassBox(double lv, double wv, double hv):Box(lv, wv, hv){}
};

ref class Stack
{
private:
	ref struct Item
	{
	    Object^ Obj;
		Item^ Next;

		Item(Object^ obj, Item^ next):Obj(obj), Next(next){}
	};
	Item^ Top;
public:
	void Push(Object^ obj)
	{
	     Top = gcnew Item(obj, Top);
	}

	Object^ Pop()
	{
		if(Top == nullptr){
		     return nullptr;
		}
		Object^ obj = Top->Obj;
		Top = Top->Next;
		return obj;
	}
};



int main(array<System::String ^> ^args)
{

	array<IContainer^>^ containers = {gcnew Box(2.0, 3.0, 4.0),
	                      gcnew GlassBox(2.0,3.0,4.0),
	                      gcnew Box(5.0,6.0,7.0),
	                      gcnew GlassBox(5.0,6.0,7.0)};
	Console::WriteLine(L"开始显示boxes的值:");
	for each(IContainer^ container in containers){
	     container->ShowVolume();
	}
	Console::WriteLine(L"现在开始入栈操作:");
	Stack^ stack = gcnew Stack;
	for each(IContainer^ container in containers){
	     stack->Push(container);
	}

	cout<<"现在开始出栈操作:";
	System::Object^ item;
	while((item = stack->Pop()) != nullptr){
	     safe_cast<IContainer^>(item)->ShowVolume();
	}
	system("pause");
    return 0;
}

  

Visual C++编程宝典(十年典藏) 明日科技 源代码 解压后287M 《Visual C++编程宝典(十年典藏)》是一本集技能、范例、项目应用为一体的学习手册,书中介绍了应用Visual C++ 6.0进行程序开发的各种技术、技巧。全书分4篇,共22章内容,其中,第1篇为技能学习篇,主要包括Visual C++集成开发环境,走进C++语言基础,运算符与表达式的应用,流程控制语句,函数的使用,面向对象程序设计,全面了解对话框,工具箱中的常用控件,高级控件,菜单、工具栏状态栏,程序中的数据库操作,程序调试等内容;第2篇为范例演练篇,主要包括生活中的算法、工作中的小工具、编程中的好帮手、图像相关工具、小游戏开发等相关范例;第3篇为项目实战篇,主要包括通信新干线、使用指纹来考勤、上机课终的屏幕监控专家、让计算机听懂声音等4个小型项目;第4篇为商业系统篇,主要包括一个大型的商业项目,即企业内部通信系统。《Visual C++编程宝典(十年典藏)》附有配套DVD光盘,光盘中提供了书中全部实例项目的源代码,这些源代码全部经过精心调试,能够在Windows XP、Windows Server 2003以及Windows 7操作系统下编译运行。《Visual C++编程宝典(十年典藏)》适用于Visual C++的初学者、编程爱好者,同时也可以作为培训机构、大中专院校老师学生的学习参考用书。
一直在找这本Ivor Horton(霍顿)写的《Visual C++2008入门经典》中文的书,据说非常经典。今天有幸终于找到了,赶紧上传大家一起分享。请下载过的朋友支持鉴定一下。 注意:网上那些所谓的《Visual C++2008入门经典》如果附件大小小于60M的,如果不是英文那肯定是假的。 文件大小:136M 页数:1142页 共6个部分 如果喜欢,请购买正! 《Visual C++2008入门经典》内容提要 内容简介: 本书系编程语言先驱者Ivor Horton的经典之作,是C++编程方面最畅销的图书品种之一,不仅涵盖了Visual C++ 2008编程知识,还全面介绍了标准C++语言C++/CLI。本书延续了Ivor Horton讲解编程语言的独特方法,从中读者可以学习Visual C++ 2008的基础知识,了解如何使用MFC进行本地ISO/ANSI C++ Windows应用程序开发以及如何使用Windows Forms进行C++/CLI Windows应用程序开发,并全面掌握在MFCWindows Forms中访问数据源的技术。此外,本书各章后面的习题将有助于读者温故而知新,并尽快成为C++高效程序员。 《Visual C++2008入门经典》图书目录 第1章 使用Visual C++ 2008编程 第2章 数据、变量计算 第3章 判断循环 第4章 数组、字符串指针 第5章 程序结构(1) 第6章 程序结构(2) 第7章 自定义数据型 第8章 深入理解 第9章 继承虚函数 第10章 标准模板库 第11章 调试技术 第12章 Windows编程的概念 第13章 使用MFC编写Windows程序 第14章 处理菜单工具栏 第15章 在窗口中绘图 第16章 创建文档改进视图 第17章 使用对话框控件 第18章 存储打印文档 第19章 编写自己的DLL 第20章 连接到数据源 第21章 更新数据源 第22章 Windows Forms应用程序进阶 第23章 在Windows Forms 应用程序中访问数据源 附录A C++关键字 附录B ASCII码 附录C Windows消息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值