Still in Love with C++ 中文版(1)

博客涉及C++、.NET在Server开发方面的内容,同时提及正则表达式的应用。这些信息技术相关内容,为Server开发提供了不同语言和工具的思路。

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


  Still in Love with C++ 中文版(1)

[  发表日期:2002-4-18 15:44:17    ]    

Still in Love with C++ 中文版

Modern Language Features Enhance the Visual C++ .NET Compiler

作者:Stanley B. Lippman

译者:荣耀


【摘要:使用C++已多年的程序员现正处于迷惑之中:他们的语言如何迎合C#和.NET的来临?本文勾画了C++如何应用于.NET世界的路标。在.NET中,可以两种方式使用C++代码:受管制的(managed)和不受管制的(unmanaged)。不受管制的代码不用CLR,而受管制的代码则致力于使用C++受管制的扩展。本文解释了这两个方式。】

我们这些C++社团里的人第一次感觉自己象是一个刚刚降临了一个新宝贝的家庭中年长的孩子—每个人都狂热地围着这个新来的小家伙,(此刻,)即便能有人轻轻地拍一下我们的脑袋,我们就很幸运了。我们很难不产生被忽视和一丁点儿伤害的感觉。在技术上这实际更糟糕,因为基础不断发生漂移,与之并进,事关生存。

当然,如今微软.NET框架是正在出售的新技术,多么丰盛的大餐啊!每一个人都对那个叫C#的语言啧啧不已。如果你是一名C++程序员,你很难不怀疑你是否应该学习C#,毕竟,在.NET讨论中,要不是拿它跟C#对比,难得提到一次C++。

C++程序员过时了吗?绝对不是!本文中,我将简介Visual Studio .NET当前版本中的新东西,并给你一些微软关于C++将来计划的概念。首先,我将简介Visual Studio.NET中C++的两个方面:标准C++和C++受管制的扩展。

保持兼容是标准C++最近进展背后的主要动机,也就是说,提供对ISO语言特性的支持。我还会讨论C++受管制的扩展,它使C++成为一种.NET语言。

Visual Studio .NET中的标准C++

标准兼容方面,已经在如下领域取得进展:

l          虚函数定义现在支持协变返回类型,对编写类层次结构的人来说,这真是个喜讯。

l          静态整型常量成员现在可被显式初始化。

l          加入了对main中隐式返回0的支持。

下面,我将简要讨论每一个领域。

加入协变返回类型是对C++语言的第一个修改(经标准委员会批准)。这是奇妙的—派生类的虚函数现在可以返回一个派生类的实例,而它所重载的基类中的虚函数返回一个基类的实例。这是对类层次结构的一个重要的设计习语支持,并且它是Visual Studio .NET中一个受欢迎的“添加剂”。

这儿有一个典型用法的例子。考察抽象基类Query:

class Query 

{

public:

virtual Query *clone() = 0;

//...

};

在派生类NotQuery实例中,clone返回一个NotQuery对象的拷贝。例如:

class NotQuery //【译注:此类的声明有点问题】



public:

   virtual ???? clone() {return new NotQuery(this);}

//...

public:

   Query *operand;

};

假如没有对协变返回类型的支持,NotQuery实例clone的返回类型必须为Query*:

//没有协变返回类型支持...

virtual Query* clone() {return new NotQuery(this);}

这会工作得很好如果你将clone的返回值赋给一个Query*指针,就象这样:

NotQuery::NotQuery(const NotQuery &rhs) {operand = rhs.operand->clone();}

但这样不成—当你希望显式将其赋给一个NotQuery*时,如下:

NotQuery nq(new NameQuery("Shakespeare"); //【译注:少了个“)”】。

//oops: 非法赋值...

NotQuery *pnq0 = nq->clone();

//ok: 需显式造型转换...

NotQuery *pnq1 = static_cast<NotQuery*>(nq->clone());

有了对协变返回类型的支持,你可以显式声明NotQuery的clone返回一个NotQuery*:

//有了协变返回类型支持...

virtual NotQuery* clone() {return new NotQuery(this);}

这就允许你用直觉的方式来使用clone,而无需显式造型转换:

//ok: 隐式转换...

Query *pq = nq->clone();

//ok: 无需转换...

NotQuery *pnq = nq->clone();

尽管静态整型常量成员的显式初始化并不象协变返回类型这样的语言特性来得那么紧要,但在类需要常量表达式的情况下,它提供了重大的设计便利,比如用于固定尺寸的数组定义中。例如:

class Buffer

{

   static const int ms_buf_size = 1024;

   char m_buffer[ms_buf_size];

};

静态整型常量成员是C++中唯一可在类定义中被显式初始化的类成员,从而使得该成员的值可被类中的其它成分使用,比如m_buffer的维数尺寸。否则,一般使用枚举作为符号常量代替。

main的返回值表示程序的退出状态。约定俗成,0表示程序成功退出。对于标准C++,没有显式返回值的main意味着编译器将在其尾部之前插入一行return 0。Visual Studio .NET中的Visual C++终于遵从了这个标准。

Visual Studio .NET中受管制的C++

Visual Studio .NET中C++受管制的扩展主要考虑以下三个应用策略:

l          对于不受管制的API,提供了受管制的.NET包装类,从而可将现存的C++类暴露给微软.NET平台。

l          可以使用微软.NET类框架,并可与不受管制的C++混用。对框架来说有三个方面:核心语言支持,例如集合类和系统I/O;基础编程类,如对线程、网络套接字和正则表达式的支持;应用领域支持,例如XML、ASP.NET、Web Services、Windows Forms和ADO.NET等等。

l          你可以直接在.NET环境中编写,就好比在C#和Visual Basic中一样。不过,这个版本中的C++还未提供对RAD设计者的支持,例如Windows Forms和Web Forms。

首先,我将讨论包装一个不受管制的实现。在我的《C++ Primer》第三版(Addison-Wesley, 1998)一书里,我创建了一个比较大的文本查询应用,它着重练习STL容器类,用以解析文本文件并建立内部表示。表1展示了包含文件,表2展示了数据表示。

表1 文本查询应用的包含文件

#include <algorithm>

#include <string>

#include <vector>

#include <utility>

#include <map>

#include <set>

#include <iostream>

#include <fstream>

#include <stddef.h>

#include <ctype.h>

using namespace std;




表2 数据表示

typedef pair<short,short> location;

typedef vector<location>  loc;

typedef vector<string>    text;

typedef pair<text*,loc*>  text_loc;

class TextQuery 

{

public:

   // ...

private:

   vector<string>     *lines_of_text;

   text_loc           *text_locations;

   map<string,loc*>   *word_map;

   Query              *query;

   static string      filt_elems;

   vector<int>        line_cnt;

};


Query是一个解释查询语言的面向对象层次结构的抽象基类。表3展示了一个查询会话的可能运行方式。文本查询系统的一个本地调用看起来和下面相似:

int main()

{

TextQuery tq;

tq.build_up_text();

tq.query_text();

}

表3 查询会话

Enter a query-please separate each item by a space. 

<script language=JavaScript> document.write(" "); document.write(""); document.write(""); </script>
  Still in Love with C++ 中文版(2)

[  发表日期:2002-4-18 15:47:42    ]    

Terminate query (or session) with a dot( . ).

==> fiery && ( bird || shyly )

       fiery ( 1 ) lines match

       bird ( 1 ) lines match

       shyly ( 1 ) lines match

        ( bird || shyly )  ( 2 ) lines match

       fiery &&  ( bird || shyly )  ( 1 ) lines match

Requested query: fiery &&  ( bird || shyly ) 

( 3 ) like a fiery bird in flight. A beautiful fiery bird, he tells her,


我希望无需做什么修修补补的事情(更不要说重新实现它了)就可将TextQuery接口暴露给.NET平台。毕竟,它能够工作。我心里没底—是不是如果我想移到.NET平台就意味着我必须放弃在本地代码上的投资。幸运地是,包装本地代码以暴露给.NET平台是受管制的C++的拿手好戏。表4展示了干这种事的代码的可能模样。

表4 包装本地C++类

#include "TextQuery.h"

__gc class TextQueryNet 

{

private:

   TextQuery *pquery;    

public:

   TextQueryNet() : pquery(new TextQuery()){}

  ~TextQueryNet() {delete pquery;}

   void query_text() {pquery->query_text();}

   void build_up_text() {pquery->build_up_text();}

  // ...

};


__gc修饰符(见表4所示)将该类标记为一个受管制的类—一个配置在CLR受管制堆上的被垃圾收集的类。我将本地类声明为指针成员,利用表达式new将其配置在不受管制的堆上,就象我在本地代码里做的一样。因为它不被垃圾收集,我在析构器里将它delete掉。build_up_text和query_text都充当存根函数,将调用调度到实际的TextQuery对象。

表5展示了修改过的main函数,它是由受管制的C++项目向导生成的。

表5 生成的main函数

#include "stdafx.h"

#using <mscorlib.dll>

#include <tchar.h>

using namespace System;

#include "gc_TextQuery.h"

int _tmain(void) 

{

    Console::WriteLine(S"Beginning managed wrapper test ...");

    TextQueryNet *tqn = new TextQueryNet();

    tqn->build_up_text();

    tqn->query_text();

Console::WriteLine(S"Ending managed wrapper test ...");

return 0;

}


现在让我们来讨论如何使用.NET框架。假如有人问我ISO标准C++最严重的缺点是什么,我会说是这样的一个事实—没有诸如线程、网络编程、正则表达式和XML等编程领域的标准库。标准委员会计划在下一轮时间里弥补这个不足,但离现在还有几年,这期间你怎么办?幸运地是,.NET框架提供了一个颇具吸引力的解决方案。例如,表6展示了一个使用了.NET框架的简单套接字服务器类。它接受对Northwind的employees的电话号码查询,Northwind是一个同Visual Studio .NET一起分发的样例SQL数据库。

表6 简单套接字服务器类

//包含必要的组合件(assemblies)

#using <mscorlib.dll>

#using <System.dll>

#using <System.Data.dll>

#using <System.Xml.dll>

//打开相关名字空间

using namespace System;

using namespace System::Threading;

using namespace System::Data;

using namespace System::Data::SqlClient;

using namespace System::Collections;

using namespace System::Net::Sockets;    

//ok: 这儿是我们的类

__gc class SocketDemo_Server 

{

private:

   static const int port = 4554;

   static const int maxPacket = 128;

   TcpListener       *tcpl;

   DataSet           *ds;

   DataRowCollection *rows;

public:

   SocketDemo_Server();

   void Start();

void handleConnection();

  //grab the data from the SQL database

   void retrieveData();

};


表7是运行这个服务器并记录其处理三个客户请求的示例输出。表8则展示了表6中所示的Start函数的实现。Start函数使用线程类来生成独立线程以从数据库中取得数据并处理客户连接。因为WriteLine需要一个引用型的参数,因此必须将port值显式装箱。

表7 服务器输出

Server[4554]: OK: started TcpListener ...

Server[4554]: OK: listening for connections ...

Server[4554]: OK: retrieved SQL database info ...



Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Fuller

Server[4554]: OK: first request for Fuller

Server[4554]: Phone number for Fuller: (206) 555-9482



Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for King

Server[4554]: OK: first request for King

Server[4554]: Phone number for King: (71) 555-5598



Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Fuller

Server[4554]: OK: cached request for Fuller

Server[4554]: Phone number for Fuller: (206) 555-9482



Server[4554]: OK: a client connected ...

Server[4554]: OK: client requested phone # for Musil

Server[4554]: OK: first request for Musil

Server[4554]: Phone number for Musil:  Sorry. Cannot be found.




表8 Start函数

void SocketDemo_Server::Start()

{

   try 

   {

       tcpl = new TcpListener(port);

       tcpl->Start();

       Console::WriteLine(S"Server[{0}]: OK: started TcpListener ...", __box( port ));

       //从数据库中取得数据 ... 


  Still in Love with C++ 中文版(3)

[  发表日期:2002-4-18 15:48:01    ]    




       Thread *tdata = new Thread(new ThreadStart(this, &SocketDemo_Server::retrieveData));

       tdata->Start(); //ok: 蹬掉线程 ...                

       //处理socket连接的线程 ...

       Thread *tconnect = 

new Thread(new ThreadStart(this, &SocketDemo_Server::handleConnection));

       tconnect->Start();

   }

   catch(Exception *ex)

   {

       Console::WriteLine(S"Oops: Unable to Set Up SocketDemo_Server");

       Console::WriteLine(ex->ToString());

   }

}


类Exception是.NET异常层次结构的根。ToString方法显示了一个完整的栈跟踪,这酷毙了。ThreadStart是一个委托类型—一种既可指向静态也可指向非静态成员函数的泛型指针。

我可以进一步探究这个实现,但我认为你已经能够得到一个对框架威力和易用性的感性认识了。更为重要的是,你可以看到,通过C++来使用它是多么得easyJ

C++的将来

希望在读完这个对Visual Studio .NET的一瞥后,能够使你打消疑虑、重树信心—Visual C++不但仍是这个家庭中成员之一,并且它还是一个重要的成员!为了突出这个重要性,微软Visual C++小组正努力工作于一个过渡版本,争取尽快交付这些特性。谈及ISO标准C++,这个小组已经以异乎寻常的步幅进行兼容性工作。对于那些牛气的程序员,这意味着模板、模板、模板。大量使用了模板的第三方库,例如Loki和Boost,现在可以在内部编译而不需要兜什么圈子了。正如好莱坞所言:在附近等我。我们不是啥都还没看见吗! 

- 全文完 - 

<script language=JavaScript> document.write(""); document.write(""); document.write(""); </script>
<script language=JavaScript> document.write(" "); document.write(""); document.write(""); </script>
<think>好的,我现在需要帮用户解决Git rebase过程中遇到中断的问题。用户的问题是“git rebase interrupted how to resolve or continue”,也就是在rebase过程中如何解决中断或继续操作。首先,我得回忆一下Git rebase的常见问题处理步骤。 首先,用户可能在进行rebase操作时遇到了冲突,或者手动中断了rebase,这时候Git会停留在中间状态,需要用户干预才能继续。常见的处理方式包括解决冲突后继续,或者跳过有问题的提交,甚至中止整个rebase过程。 接下来,我需要整理出具体的解决步骤。根据经验,处理中断的rebase通常有以下几个步骤: 1. **解决冲突**:当rebase因为冲突中断时,用户需要手动编辑文件解决冲突,然后使用`git add`标记为已解决,再执行`git rebase --continue`继续。这时候可能需要检查冲突文件,确保修改正确。 2. **跳过当前提交**:如果某个提交导致问题,用户可以选择用`git rebase --skip`跳过该提交。但要注意这可能丢失该提交的更改,需要谨慎使用。 3. **中止rebase**:如果情况变得复杂,用户可能需要完全取消rebase,回到操作前的状态,这时候使用`git rebase --abort`。 另外,用户可能还需要查看当前状态,使用`git status`来了解哪些文件有冲突,或者需要处理哪些步骤。同时,查看提交历史`git log`或使用图形化工具如`gitk`可以帮助理解当前状态。 需要确保用户理解每个步骤的风险。例如,使用`--skip`可能会丢失提交,而`--abort`会完全撤销rebase,回到分支原来的状态。在继续或跳过之前,用户应该确认解决冲突的方式是否正确,或者是否需要跳过某个提交。 另外,用户可能会遇到更复杂的情况,比如在解决冲突后再次出现冲突,这时候需要重复解决步骤,直到所有提交都被处理完毕。或者,用户可能需要手动编辑提交历史,使用`git rebase --edit-todo`来调整提交顺序或修改提交信息。 还需要提醒用户,在rebase过程中,最好保持工作目录的干净,避免未提交的更改影响操作。如果有未提交的修改,应该先使用`git stash`保存起来,再进行rebase。 最后,根据用户提供的引用内容,引用[1]提到了使用`git rebase <basebranch> <topicbranch>`的命令,这可能是在说明如何开始一个rebase操作,但用户的问题是关于中断后的处理。引用[2]提到了文件联系中断的情况,可能需要恢复联系或找回代码,这可能与rebase过程中文件冲突或状态异常有关,用户需要根据具体情况选择同步状态或恢复代码。 综合以上思考,我需要将解决步骤分点列出,确保用户能够逐步操作。同时,生成相关问题,帮助用户深入理解rebase的其他方面,比如解决冲突后的提交、处理多个冲突等。</think>### 解决 Git Rebase 中断问题的步骤 当 Git rebase 操作因冲突或手动中断导致流程暂停时,可按以下步骤处理: #### 1. **查看当前状态** - 运行命令确认 rebase 状态和冲突文件: ```bash git status ``` 输出会提示需要解决的冲突文件路径[^2]。 #### 2. **解决冲突** - 手动编辑标记为冲突的文件(如 `file.txt`),删除冲突标记(`<<<<<<<`、`=======`、`>>>>>>>`),保留需要的代码。 - 标记冲突已解决: ```bash git add file.txt ``` #### 3. **继续 Rebase** - 完成所有冲突修复后,继续 rebase 流程: ```bash git rebase --continue ``` - 若需跳过当前提交(可能导致数据丢失): ```bash git rebase --skip ``` #### 4. **中止 Rebase** - 若需完全放弃当前 rebase 操作,恢复原始分支状态: ```bash git rebase --abort ``` #### 5. **验证结果** - 使用 `git log` 检查提交历史是否按预期调整: ```bash git log --oneline --graph ``` --- ### 关键操作对比 | 操作 | 用途 | 风险提示 | |---------------------|-----------------------------------|-----------------------------| | `git rebase --continue` | 正常继续 rebase | 需确保所有冲突已正确解决 | | `git rebase --skip` | 跳过导致问题的提交 | 可能丢失该提交的修改 | | `git rebase --abort` | 彻底终止 rebase,还原分支原状态 | 放弃所有未完成的 rebase 操作 | --- ### 示例场景 假设 rebase 因 `file.py` 冲突中断: 1. 修改 `file.py` 后执行: ```bash git add file.py git rebase --continue ``` 2. Git 会继续应用后续提交,直至全部完成。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值