其实如果明白exchange的一些相关组成会更好的解决此类问题:
个人推测,exchange采用了wcf服务,而此服务寄宿到iis下,所以首先要启动iis,然后才能启动exchange控制台来进行相关操作。
初始化失败,最大的可能性就是iis无法启动服务(80端口可能被其它程序占用,特此说明好像换成其它端口,exchange好像也是无法初始化,不知是否哪里可更改),所以要先分步来解决。
转自:http://www.cnblogs.com/superpcer/archive/2012/05/22/2512816.html
对初步创业的软件企业的思考
1.企业创业背景
软件企业创业背景无非三种情形:1创业者(一般技术出身)有个idea,前期有笔资金,想做点东西,觉得这个产品会有市场,一般是通用产品,然后带着一个team开始开发产品,成立公司;2投资人有个idea,一般这个idea都是跟投资人自己所处的行业有点相关,然后去找一个具有开发这个产品能力的team,成立公司,寻找风投。3创业者有一定的人脉关系,手头上有很多项目,寻找一个团队,成立公司,不停的做项目。
以上三种完全映射了软件行业的三类主要盈利模式:第一种映射了通用产品模式,开发方自己出钱研制产品,产权属于自己,产品具有一定的通用性,可以卖给任何目标客户,而不是只卖给一个客户;第二种映射了运营模式,运营不是一次性消费,而是持续消费,通过用户不断的使用运营商的产品或服务,使运营商持续获益。第三种映射了合同模式,合同模式相对门槛较低,创业起步比较容易。
关于公司培养学习型组织是好的,不过目的我觉得不太对,不应该把书定死在那几本,哪些都是管理相关的书,你不清楚员工的兴趣,应该让他们看他们感兴趣的书,既然已经是培养了,不应该都往这个方向培养,从他们选择的书中,你可以做到知人善用。培养出各方面的人才
2.企业现状
1.管理执行力低:表现在管理者不了解下属的长处和短处,导致不能人尽其才,人尽其用,工作分配下去执行力度不够。管理者要了解团队,知道团队的每一件事,每一件事的难易程度,做到任何的合理分配,注重员工的工作成果,这样员工才感受到在这个团队内有得到重用的感觉,才会尽力把每件事情做好,管理执行力自然就高起来了。
2.员工自觉性低:人的自觉性低是比较天生的,靠自觉来杜绝一些事情是很困难的,所以公司需要一定的制度和文化。
3.缺少系统的管理流程
4.缺少系统的研发流程
5.缺少核心技术力量
针对这些以上五点,我会在企业管理和企业文化中来说明如何解决这些不良现状。
3.企业管理
企业管理到底管什么,怎么管,谁来管?管理的目标又是什么?
我对这个问题做了以下思考:企业管理可以总结为管人和管事。管人怎么管,管事怎么管,管人就需要公司有一套严格的,可执行性很强的流程制度,来约束员工的任何行为,并引导员工如何去做好自己的每一件事,是用流程去引导,不是去强迫。管事,就是指要分配一项工作该由谁来胜任,谁最适合做这件事情,且用什么方法去做这件事情,对于在这方面已经有经验的,当然让这方面有经验的人来做这件事,这里就涉及到成功经验的管理,这样就算有经验的人不在了,也可以让后人根据这个经验去做好这件事情。这里又反映出领导知人善用的问题,如果不会知人善用,领导的决策和执行肯定就都会出问题。“知人”是指管理者非常了解团队成员,包括每个人的知识技能和性格爱好等;“善用”是指让团队各成员扬长避短,是团队战斗力达到最强。“善用”建立在“知人”基础之上。
三国演义里面有个故事叫“马谡失街亭”,有两个教训值得我们学习:
(1)马谡没有按照诸葛亮的指示来执行,自作聪明,丢了街亭。他犯的是执行层面的错误,按律(流程制度)被斩。
(2)诸葛亮错误的让马谡去守街亭,不能知人善用,他犯了决策的错误。由于不能斩自己,只好按律(流程制度)斩了马谡。
所以建立合理的规章制度很重要,规章制度不应该多而杂,应该精而简,摈弃那些对本企业完全没用的,用了也没有任何好处的制度,留下那些确实能让企业做到管人管事的制度,制度不是摆设,一定要贯彻执行。
以下我列下我认为软件企业需要用到的制度和规范:
1)惩罚管理制度
2)绩效考核管理制度
3)办公环境氛围管理制度
4)公司资产管理制度(无形,有形)
5)评审、讨论、开会、管理规范。
6)需求调研,需求分析,系统设计,架构设计,数据库设计,系统测试,开发编码,都需要有规范。
针对以上几点最好能做到有软件来辅助员工来执行这些流程和制度,这样在使用软件的时候就等同于执行了某个流程,否则有点纸上谈兵。
谁来管?肯定是上级管下级,最好不要出现跨级别管,或跳级别管,下级的错,上级肯定有责任的,不要一有问题,就一级级往下责怪,员工之所以上班工作懒散,玩游戏,聊天,大部分是因为他们手头上没有实际上的任务要做,加上人本来自觉性不高,就会去找些其他的事情做做,只要你领导上级有任务一个个分配下来,相信他们肯定会任务优先完成,就算真的没有实际工作的任务可以分配,也可以布置些学习型的任务,对他们以后有帮助的,对企业将来有用的任务,而且任务最好是以天为单位,不宜时间太长,这样员工其实也会觉得领导有再重用他们,有在培养他们。现在小公司应该普遍存在一个想象,项目经理或技术牛人忙死,下面的人做不了事情空死,极度不平衡。
管理的目标?答:正确决策和正确执行。
正确决策主要体现在:
(1)用正确的人:即用能为企业创造效益的人。
(2)开发正确的产品:即开发能为企业赚取利润的产品。
正确执行主要体现在:
(1)正确的用人:即让人们为企业创造尽可能多的效益。
(2)正确的开发产品:即把产品做得“又好又快又省钱”,为企业赚取更多利润。
4.企业(团队)文化
对于初创企业谈企业文化感觉有大了,这里我就讲下我理解的Team文化,从几个问题入手:1)一个团队应该具有什么样的素质?
2)一个团队应该具备什么样的人才?
3)一个团队应该具备什么样的氛围?
1.团队素质:团队应该具有团队精神,杜绝个人主义,英雄主义。能够虚心接受团队意见的,凡事都以团队利益为最大化的,团队间要互相帮助,互相提醒,互相鼓励,不要互相打击,不斤斤计较,不要总看着谁谁比自己多拿了,谁谁比自己少做了,做事要有毅力,有耐力,不要遇到点挫折就放弃。
2.团队人才:至少一个技术牛人,但不能都是技术牛人,所谓一山不容二虎,一团队也不容2牛人,在同个领域都强的人最好不要让他们挤在一起。至少一个懂得协调团队各方面工作气氛的人,能够在客户那做“3陪 “的人。要有一个美工,视觉很强的人,对产品的界面交互设计有精益求精的精神。要有一个很了解市场,业务分析能力很强的人,能将实际业务抽象出来,在软件上体现。要有能带领一个团队,能做出良好的战略,有魄力,不优柔寡断,做事情有一定决策力的人。当然还要甘愿不辞辛劳的人,上级分配什么工作就很认真的做完分配工作。
3.团队氛围:做事要有干劲,配合要有默契,战斗要有目标,团结不可懒散,勇猛不可退缩。
5.企业核心竞争力
今天无论哪个企业,人们都在讲核心竞争力,如果把核心竞争力说的通俗一些,就是技能,就是我而你没有的,我有但你无法模范的,我有的但你无法替代的技能。一个人,一个团队,一家公司,一个企业,如果有了这样的本事,自然就有了生存之本和发展之道。
技术核心力量,如果在同行业内,你能做的比别人突出,这是你的核心竞争力;团队凝聚力,初创企业这个应该做的更好,如果你的团队具有很强的凝聚力,这是你的核心竞争力。
对于初创企业好的领导人和管理者,我觉得也应该是你的核心竞争力。
引用看到过的一段话:一个团队的好坏,直接取决于团队的领导人和管理者,领导人的胸怀直接决定着团队的好坏。团队的成功,主管的功劳只占10%,但团队的失败主管的责任却应该负90%。如何做一个优秀的团队主管;首先,必须有吸引住他人的人格魅力。其次,要有良好的合作心态。好的合作心态可以使你跟伙伴之间的合作关系更融洽更紧密,只有这样,团队才可以不断的发展壮大。
从dotA引申出团队的管理,dota是一个团队游戏,10人团队游戏,5v5,由哪方先拆掉对面的生命之树为游戏的最终胜利,整个游戏可以分为前期,中期,和后期,前期可能还不用团起来打战,大家都在那里正反补兵,打钱,出装备,这是基本功,这相当于企业的前期,你每个人的基本功一定要扎实,这样等有了产品要做了,你们才拿的出来你的能力和水平,不至于到了团战(做产品),发现自己身上一点装备(自身技能)都没有,
死的很快。
既然dota是一个团队游戏,那么肯定团队里面有个领导者,一般dota里面都有开黑和路人两种概念,开黑一般是指几个认识的朋友在一个队伍里面,路人就是大家都不认识的凑到了一个队伍,开黑的基本上都是胜率很高的,这是团队的默契,团队的凝聚力起的作用,每次反思自己玩路人,前期混的很好,自身装备起来很快,而且单打抓人,前期都是赢的,一旦团起来,靠你自身力量,加上队友配合不行,而对面开黑的团起来打的很好,几次团的失败,最终就导致整个游戏的失败。当然如果路人这边每个人基本功都很好,再加上有个能带领团队gank(几个人团起来抓人,埋伏),队友也能听你指挥,这个赢的也是比较高的。所以领导的能力,团队的配合,团队每个成员的基本功,是非常重要的。
虽然游戏重来一局很方便,但是企业想要重来是很困难的,人生根本就没的给你重来。
既然是很虚设的东西,初创企业应该摒弃,关于绩效考核,做的好当然是好,但是很难做好,一般都会照成反差效果,尤其对绩效考核分数算法上要有很深入的研究。员工自评:一定要让员工写事实就是的东西,别写表面的东西,好坏都可以写。
http://ajaxcontroltoolkit.codeplex.com/
The Ajax Control Toolkit contains a rich set of controls that you can use to build highly responsive and interactive Ajax-enabled Web applications. The Ajax Control Toolkit contains more than 40 controls, including the AutoComplete, CollapsiblePanel, ColorPicker, MaskedEdit, Calendar, Accordion, HTML Editor Extender, and Watermark controls. Using the Ajax Control Toolkit, you can build Ajax-enabled ASP.NET Web Forms applications by dragging-and-dropping Toolkit controls from the Visual Studio Toolbox onto an ASP.NET Web Forms page.
The latest release of the AJAX Control Toolkit is May 2012! Check out some of the new features at the announcement at Stephen Walther's blog post including the new AjaxFileUpload control and the improvements to the HtmlEditorExtender control.
To view an interactive Web site that demonstrates each of the Ajax Control Toolkit controls, visit the Ajax Control Toolkit Sample Site. The official website for the Ajax Control Toolkit -- which contains reference documentation, tutorials, and answers to frequently asked questions -- is located athttp://www.asp.net/ajaxlibrary/.
Visual Studio 2008 users, click the Downloads tab above and select the .NET 3.5 version of the toolkit.
Visual Studio 2010 users, install the ASP.NET AJAX Control Toolkit in seconds via NuGet:
The easiest way to install the Ajax Control Toolkit into a Visual Studio 2010 project is via NuGet.
It's easy! If you don't have NuGet, it's a very quick installation.
First, from with an ASP.NET Web Forms project in Visual Studio, install the AjaxControlToolkit package, eitherfrom the GUI or from the Package Manager Console.
Next, for example, register the AjaxControlToolkit at the top of the page (or in the web.config for the whole project)
<%@ Register TagPrefix="asp" Namespace="AjaxControlToolkit" Assembly="AjaxControlToolkit"%>
Now, add a ToolkitScriptManager and use some of the controls! Here's how to turn a TextBox into a rich HTML editor.
<asp:ToolkitScriptManager runat="Server" /> <asp:TextBox ID="txtComments" TextMode="MultiLine" Columns="60" Rows="8" runat="server" /> <asp:HtmlEditorExtender TargetControlID="txtComments" runat="server" />
Which gives you this:
There's lots more to see in the AJAX Control Toolkit, so have fun exploring...Enjoy!
Last edited May 2 at 12:50 AM by Superexpert, version 88
一、进程间通讯的方式
进程间通讯的方式有很多,常用的有共享内存(内存映射文件、共享内存DLL、剪切板等)、命名管道和匿名管道、发送消息等几种方法来直接完成,另外还可以通过socket口、配置文件和注册表等来间接实现进程间数据通讯任务。以上这几种方法各有优缺点,具体到在进程间进行大数据量数据的快速交换问题上,则可以排除使用配置文件和注册表的方法;另外,由于管道和socket套接字的使用需要有网卡的支持,因此也可以不予考虑。这样,可供选择的通讯方式只剩下共享内存和发送消息两种。
二、发送消息实现进程间通讯前准备
下面的例子用到一个windows api 32函数
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr wnd,int msg,IntPtr wP,IntPtr lP);
要有此函数,需要添加using System.Runtime.InteropServices;命名空间
此方法各个参数表示的意义
wnd:接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
msg:指定被发送的消息类型。
wP:消息内容。
lP:指定附加的消息指定信息。
用api参考手册查看SendMessage用法时,参考手册则提示
SendMessage与PostMessage之间的区别:SendMessage和PostMessage,这两个函数虽然功能非常相似,都是负责向指定的窗口发送消息,但是SendMessage() 函数发出消息后一直等到接收方的消息响应函数处理完之后才能返回,并能够得到返回值,在此期间发送方程序将被阻塞,SendMessage() 后面的语句不能被继续执行,即是说此方法是同步的。而PostMessage() 函数在发出消息后马上返回,其后语句能够被立即执行,但是无法获取接收方的消息处理返回值,即是说此方法是异步的。
三、发送消息实现进程间通讯具体步骤
1.新建windows应用程序
(1)打开VS2008,新建一个“windows 应用程序”,主窗口为Form1,项目名称:ProcessCommunication
(2)在Form1上添加一个标签为textBox1的文本框,并为Form1添加KeyDown事件,当Form1接收到KewDown消息时,将接收到的数据显示在label1上。
public Form1()
{
InitializeComponent();
this.KeyDown+=new KeyEventHandler(Form1_KeyDown);
}
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
this.textBox1.Text = Convert.ToString(e.KeyValue);
}
(3)编译运行,生成ProcessCommunication.exe
2.新建windows应用程序
(1)打开VS2008,新建一个“windows 应用程序”,主窗口为Form1,项目名称:ProcessCommunication1,
并在Form1上添加一个按钮和一个文本框
namespace ProcessCommunication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
//Win32 API函数:
[DllImport("User32.dll", EntryPoint = "SendMessage")]
private static extern int SendMessage(IntPtr wnd,int msg,IntPtr wP,IntPtr lP);
private void button1_Click(object sender, EventArgs e)
{
Process[] pros = Process.GetProcesses(); //获取本机所有进程
for (int i = 0; i < pros.Length; i++)
{
if (pros[i].ProcessName == "ProcessCommunication") //名称为ProcessCommunication的进程
{
IntPtr hWnd = pros[i].MainWindowHandle; //获取ProcessCommunication.exe主窗口句柄
int data = Convert.ToInt32(this.textBox1.Text); //获取文本框数据
SendMessage(hWnd, 0x0100, (IntPtr)data, (IntPtr)0); //点击该按钮,以文本框数据为参数,向Form1发送WM_KEYDOWN消息
}
}
}
}
}
3.启动ProcessCommunication.exe可执行文件,弹出Form1窗体称为接受消息窗体。
启动ProcessCommunication1.exe可执行文件,在弹出的窗体中的文本框中输入任意数字,点击button1按钮,接受消息窗体textBox1即显示该数字。
到此结束。
http://www.cnblogs.com/realyan/archive/2011/07/14/2106339.html
虚函数的定义:
虚函数必须是类的非静态成员函数(且非构造函数),其访问权限是public(可以定义为private or proteceted, 但是对于多态来说,没有意义。),在基类的类定义中定义虚函数的一般形式:
virtual 函数返回值类型 虚函数名(形参表)
{ 函数体 }
虚函数的作用是实现动态联编,也就是在程序的运行阶段动态地选择合适的成员函数,在定义了虚函数后,
可以在基类的派生类中对虚函数重新定义(形式也是:virtual 函数返回值类型 虚函数名(形参表){ 函数体 }),在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型。以实现统一的接口,不同定义过程。如果在派生类中没有对虚函数重新定义,则它继承其基类的虚函数。当程序发现虚函数名前的关键字virtual后,会自动将其作为动态联编处理,即在程序运行时动态地选择合适的成员函数。
实现动态联编需要三个条件:
1、 必须把需要动态联编的行为定义为类的公共属性的虚函数。
2、 类之间存在子类型关系,一般表现为一个类从另一个类公有派生而来。
3、 必须先使用基类指针指向子类型的对象,然后直接或者间接使用基类指针调用虚函数。
定义虚函数的限制:
(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
(2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
(3)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、参数类型都相同的非虚函数。在以该类为基类的派生类中,也不能出现这种非虚的同名同返回值同参数个数同参数类型函数。
为什么虚函数必须是类的成员函数:
虚函数诞生的目的就是为了实现多态,在类外定义虚函数毫无实际用处。
为什么类的静态成员函数不能为虚函数:
如果定义为虚函数,那么它就是动态绑定的,也就是在派生类中可以被覆盖的,这与静态成员函数的定义(:在内存中只有一份拷贝;通过类名或对象引用访问静态成员)本身就是相矛盾的。
为什么构造函数不能为虚函数:
因为如果构造函数为虚函数的话,它将在执行期间被构造,而执行期则需要对象已经建立,构造函数所完成的工作就是为了建立合适的对象,因此在没有构建好的对象上不可能执行多态(虚函数的目的就在于实现多态性)的工作。在继承体系中,构造的顺序就是从基类到派生类,其目的就在于确保对象能够成功地构建。构造函数同时承担着虚函数表的建立,如果它本身都是虚函数的话,如何确保vtbl的构建成功呢?
注意:当基类的构造函数内部有虚函数时,会出现什么情况呢?结果是在构造函数中,虚函数机制不起作用了,调用虚函数如同调用一般的成员函数一样。当基类的析构函数内部有虚函数时,又如何工作呢?与构造函数相同,只有“局部”的版本被调用。但是,行为相同,原因是不一样的。构造函数只能调用“局部”版本,是因为调用时还没有派生类版本的信息。析构函数则是因为派生类版本的信息已经不可靠了。我们知道,析构函数的调用顺序与构造函数相反,是从派生类的析构函数到基类的析构函数。当某个类的析构函数被调用时,其派生类的析构函数已经被调用了,相应的数据也已被丢失,如果再调用虚函数的派生类的版本,就相当于对一些不可靠的数据进行操作,这是非常危险的。因此,在析构函数中,虚函数机制也是不起作用的。
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码(Or 不变的 接口)来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。
关于虚函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从虚函数的实现机制上面为大家一个清晰的剖析。
当然,相同的文章在网上也出现过一些了,但我总感觉这些文章不是很容易阅读,大段大段的代码,没有图片,没有详细的说明,没有比较,没有举一反三。不利于学习和阅读,所以这是我想写下这篇文章的原因。也希望大家多给我提意见
言归正传,让我们一起进入虚函数的世界。
虚函数表
对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例(注:抽象类即有纯虚函数的类不能被实例化。)中这个表被分配在了这个实例的内存中(注:一个类的虚函数表是静态的,也就是说对这个类的每个实例,他的虚函数表的是固定的,不会为每个实例生成一个相应的虚函数表。),所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
这里我们着重看一下这张虚函数表。在C++的标准规格说明书中说到,编译器必需要保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证正确取到虚函数的偏移量)。这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
假设我们有这样的一个类:
|
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的实例来得到Base的虚函数表。 下面是实际例程:
|
{ ... typedef void(*Fun)(void); Base b; Fun pFun = NULL; cout << "虚函数表地址:" << (int*)(&b) << endl; cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl; // Invoke the first virtual function pFun = (Fun)*((int*)*(int*)(&b)); pFun(); ... } |
实际运行经果如下(Windows XP+VS2003, Linux 2.6.22 + GCC 4.1.3) :
虚函数表地址:0012FED4
虚函数表 — 第一个函数地址:0044F148
Base::f
通过这个示例,我们可以看到,我们可以通过强行把&b转成int *,取得虚函数表的地址,然后,再次取址就可以得到第一个虚函数的地址了,也就是Base::f(),这在上面的程序中得到了验证(把int* 强制转成了函数指针)。通过这个示例,我们就可以知道如果要调用Base::g()和Base::h(),其代码如下:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
画个图解释一下。如下所示:
注意:在上面这个图中,我在虚函数表的最后多加了一个结点,这是虚函数表的结束结点,就像字符串的结束符“\0”一样,其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。
在WinXP+VS2003下,这个值是NULL。
而在Ubuntu 7.10 + Linux 2.6.22 + GCC 4.1.3下,这个值是如果1,表示还有下一个虚函数表,如果值是0,表示是最后一个虚函数表。
下面,我将分别说明“无覆盖”和“有覆盖”时的子类虚函数表的样子。没有覆盖父类的虚函数是毫无意义的。我之所以要讲述没有覆盖的情况,主要目的是为了给一个对比。在比较之下,我们可以更加清楚地知道其内部的具体实现。
一般继承(无虚函数覆盖)
下面,再让我们来看看继承时的虚函数表是什么样的。假设有如下所示的一个继承关系:
请注意,在这个继承关系中,子类没有重写任何父类的函数。那么,在派生类的实例的虚函数表如下所示:
对于实例:Derive d; 的虚函数表如下: (overload(重载) 和 override(重写),重载就是所谓的名同而签名不同,重写就是对子类对虚函数的重新实现。)
我们可以看到下面几点:
1)虚函数按照其声明顺序放于表中。
2)父类的虚函数在子类的虚函数前面。
一般继承(有虚函数覆盖)
覆盖父类的虚函数是很显然的事情,不然,虚函数就变得毫无意义。下面,我们来看一下,如果子类中有虚函数重载了父类的虚函数,会是一个什么样子?假设,我们有下面这样的一个继承关系。
为了让大家看到被继承过后的效果,在这个类的设计中,我只覆盖了父类的一个函数:f()。那么,对于派生类的实例的虚函数表会是下面的样子:
我们从表中可以看到下面几点,
1)覆盖的f()函数被放到了子类虚函数表中原来父类虚函数的位置。
2)没有被覆盖的函数依旧。
这样,我们就可以看到对于下面这样的程序,
Base *b = new Derive();
b->f();
由b所指的内存中的虚函数表(子类的虚函数表)的f()的位置已经被Derive::f()函数地址所取代,于是在实际调用发生时,是Derive::f()被调用了。这就实现了多态。
多重继承(无虚函数覆盖)
下面,再让我们来看看多重继承中的情况,假设有下面这样一个类的继承关系。注意:子类并没有覆盖父类的函数。
对于子类实例中的虚函数表,是下面这个样子:
我们可以看到:
1) 每个父类都有自己的虚表。
2) 子类的成员函数被放到了第一个父类的表中。(所谓的第一个父类是按照声明顺序来判断的)
这样做就是为了解决不同的父类类型的指针指向同一个子类实例,而能够调用到实际的函数。
多重继承(有虚函数覆盖)
下面我们再来看看,如果发生虚函数覆盖的情况。
下图中,我们在子类中覆盖了父类的f()函数。
下面是对于子类实例中的虚函数表的图:
我们可以看见,三个父类虚函数表中的f()的位置被替换成了子类的函数指针。这样,我们就可以用任一个父类指针来指向子类,并调用子类的f()了。如:
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()
安全性
每次写C++的文章,总免不了要批判一下C++。这篇文章也不例外。通过上面的讲述,相信我们对虚函数表有一个比较细致的了解了。水可载舟,亦可覆舟。下面,让我们来看看我们可以用虚函数表来干点什么坏事吧。
一、尝试:通过父类型的指针(指向子类对象)访问子类自己的虚函数
我们知道,子类没有重载父类的虚函数是一件毫无意义的事情。因为多态也是要基于函数重载的。虽然在上面的图中我们可以看到子类的虚表中有Derive自己的虚函数,但我们根本不可能使用基类的指针来调用子类的自有虚函数:
Base1 *b1 = new Derive();
b1->f1(); //编译出错
任何妄图使用父类指针想调用子类中的未覆盖父类的成员函数的行为都会被编译器视为非法,所以,这样的程序根本无法编译通过。
但在运行时,我们可以通过指针的方式访问虚函数表来达到违反C++语义的行为。
二、尝试:通过父类型的指针(指向子类对象)访问父类的non-public虚函数
另外,如果父类的虚函数是private或是protected的,但这些非public的虚函数同样会存在于子类虚函数表中,所以我们同样可以使用访问虚函数表的方式来访问这些non-public的虚函数,这是很容易做到的。
如:
|
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(); } |
结束语
C++这门语言是一门Magic的语言,对于程序员来说,我们似乎永远摸不清楚这门语言背着我们在干了什么。需要熟悉这门语言,我们就必需要了解C++里面的那些东西,需要去了解C++中那些危险的东西。不然,这是一种搬起石头砸自己脚的编程语言。
http://www.dreamincode.net/code/snippet2661.htm
/*
* A method to convert BBCode to HTML
* Author: Danny Battison
* Contact: gabehabe@googlemail.com
*/
/// <summary>
/// A method to convert basic BBCode to HTML
/// </summary>
/// <param name="str">A string formatted in BBCode</param>
/// <returns>The HTML representation of the BBCode string</returns>
public string ConvertBBCodeToHTML (string str)
{
Regex exp;
// format the bold tags: [b][/b]
// becomes: <strong></strong>
exp = new Regex(@"\[b\](.+?)\[/b\]");
str = exp.Replace(str, "<strong>$1</strong>");
// format the italic tags: [i][/i]
// becomes: <em></em>
exp = new Regex(@"\[i\](.+?)\[/i\]");
str = exp.Replace(str, "<em>$1</em>");
// format the underline tags: [u][/u]
// becomes: <u></u>
exp = new Regex(@"\[u\](.+?)\[/u\]");
str = exp.Replace(str, "<u>$1</u>");
// format the strike tags: [s][/s]
// becomes: <strike></strike>
exp = new Regex(@"\[s\](.+?)\[/s\]");
str = exp.Replace(str, "<strike>$1</strike>");
// format the url tags: [url=www.website.com]my site[/url]
// becomes: <a href="www.website.com">my site</a>
exp = new Regex(@"\[url\=([^\]]+)\]([^\]]+)\[/url\]");
str = exp.Replace(str, "<a href=\"$1\">$2</a>");
// format the img tags: [img]www.website.com/img/image.jpeg[/img]
// becomes: <img src="www.website.com/img/image.jpeg" />
exp = new Regex(@"\[img\]([^\]]+)\[/img\]");
str = exp.Replace(str, "<img src=\"$1\" />");
// format img tags with alt: [img=www.website.com/img/image.jpeg]this is the alt text[/img]
// becomes: <img src="www.website.com/img/image.jpeg" alt="this is the alt text" />
exp = new Regex(@"\[img\=([^\]]+)\]([^\]]+)\[/img\]");
str = exp.Replace(str, "<img src=\"$1\" alt=\"$2\" />");
//format the colour tags: [color=red][/color]
// becomes: <font color="red"></font>
// supports UK English and US English spelling of colour/color
exp = new Regex(@"\[color\=([^\]]+)\]([^\]]+)\[/color\]");
str = exp.Replace(str, "<font color=\"$1\">$2</font>");
exp = new Regex(@"\[colour\=([^\]]+)\]([^\]]+)\[/colour\]");
str = exp.Replace(str, "<font color=\"$1\">$2</font>");
// format the size tags: [size=3][/size]
// becomes: <font size="+3"></font>
exp = new Regex(@"\[size\=([^\]]+)\]([^\]]+)\[/size\]");
str = exp.Replace(str, "<font size=\"+$1\">$2</font>");
// lastly, replace any new line characters with <br />
str = str.Replace("\r\n", "<br />\r\n");
return str;
}










