一数据结构与数据类型
1.1指针
在C++中,可以对指针进行很方便的操作,还可以通过reinpreter_cast<type-id> (expression)在指针与整型之间进行转换;而在C# 中将指针这个概念隐藏,仅通过unsafe才可以使用指针。
[C#]
static void Main(string[] args)
{
unsafe
{
int i = 5;
int* pI = &i;
Console.WriteLine(i);
*pI = 100;
Console.WriteLine(*pI); }
Console.ReadLine();
}
输出 5 10
[C++]
int _tmain(int argc, _TCHAR* argv[])
{
int* pi=new int;
*pi=100;
cout<<*pi<<endl;
delete pi;}
输出100
1.2数组
C#和C++声明数组的方式不一样,主要是[]的位置不一致。
[C#]
int[] arr = {1,2,5,4};
[C++]
int arr[10]={1};
1.3 Bool类型
在C#中Bool类型不可以和整型等隐式转换,而在C++中,Bool类型实际上是整型,占有一个字节,可以与整型相互转换。
1.4 long 类型
在C#中long占有8个字节,即64位;C++中long占有4个字节。
1.5函数指针与委托
在C#中通过委托Delegate的方式实现C++中函数指针的概念。
[C#]
public delegate void TestDelegate(int i); static void TestMethod(int i)
{
Console.WriteLine(i);
} static void Main(string[] args)
{
TestDelegate testDelegate = TestMethod;
testDelegate.Invoke(100);}
输出100
[C++]
int _tmain(int argc, _TCHAR* argv[])
{
void testMethod(int i);
void (*pMethod)(int i);
pMethod = testMethod;
pMethod(100);}void testMethod(int i)
{
cout<<i<<endl;
}
输出100
1.6值类型与引用类型以及内存分配
在C#中,一个很重要的概念即为值类型与引用类型,如值类型包括一般的整型,结构体,枚举等等,不同数据类型,在数据分配的时候有很大的区别;而C++中没有值类型和引用类型之分,而在于定义在不同地方的变量有不同的访问性和不同的内存分配,主要分为自动存储(包括Register寄存器中的存储),静态存储,动态存储三种存储类型。在C++中通过new关键字均为动态存储。
在C# 中,内存可以自动回收,而C++中程序员需要手动的删除动态分为的存储空间。
C#中变量未初始化前不能使用,而C++中定义变量会自动使用默认构造函数进行初始化操作。
1.7字符串
在C#中字符串是一个对象,包含了很多种操作方法,而在C++中字符串仅是字符的一个数组,且数组最后元素为空字符'\0’。
1.8位段与共同体union
C#不支持位段和共同体,而C++继承了C的所有特性支持以上两个特性。
二面向对象
2.1接口
在C# 中接口通过interface来定义,一个类可以实现多个接口,接口之间可以继承;而C++中没有明显接口的概念,接口通过抽象类来实现。
[C#]
public interface ITestInterface
{
void Test();
}
[C++]
class TestClass
{
public:
virtual void Test()=0;//pure virtual function
}
2.2多重继承
在C#中一个类仅能继承一个父类,但在C++中一个类可以继承多个类,并且继承修饰符包括public, private, protected继承。public 继承描述一种is-a的关系,而private继承一般用于实现has-a的关系,protected继承是private的特殊情况,不同点在于允许第三代子类访问父类中的protected方法。如果不同父类继承自同一个基类,为了避免子类中有多个父类的副本,可以使用virtual实现。
[C#]
public interface ITestInterface
{
void Test();
} public class A
{
public virtual void Test()
{ }
} public class B : A,ITestInterface
{
public override void Test()
{
Console.WriteLine("Test");
base.Test();
}
}
[C++]
class TestClass
{
public:
virtual void TestMethod()=0;//pure virtual function
}
void TestClass::TestMethod()
{
cout<<"Test"<<endl;
}
class A
{
public:
inline void TestMethod(){cout<<"Test"<<endl;};
}class B:public A, private TestClass
{
public:
inline void TestB(){A::TestMethod();};
}
类B继承自A和TestClass两个类,由于两个父类均包含同一个方法名,因此用类名称进行限定。
2.3方法重载
在C#中方法重载通过override关键字来实现,还可以通过new来隐藏基类中的方法;C++中方法重载无需关键字override。C++中虚方法virtual必须通过指针进行访问,且借助虚函数实现了多态性(具体跟虚函数表有关)。
2.4 friend与私有字段访问
在C# 中,使用private的成员,在类之外无法直接方法;在C++中可以通过friend允许外部类及其成员进行方法。
[C++]
class CA
{
private:
int i;
public:
friend class CB;
inline CA(int j=10){
i=j;
};
inline void test()const
{
cout<<i<<endl;
};
};class CB
{
public:
void test(CA& a) const;
};void CB::test(CA& a) const
{
a.i+=1;
cout<<a.i<<endl;
};int _tmain(int argc, _TCHAR* argv[])
{
CA a=90;
CB b;
a.test();
b.test(a);
a.test();}
输出90 91 91
2.5 RTTI运行时信息与cast
在C#中可以通过as进行类型的安全转换;而在C#中可以使用dynamic_cast操作符进行安全的向上向下转换,除此之外还包括const_cast,static_const(转换失败会抛出异常),reinpreter_cast进行数据的转换。C#和C++都可以使用类似C风格的强制转换,不同一点是C#的单个参数的构造函数可以隐式的进行强制转换。
C#中可以通过typeof操作符来获取对象的运行时类型信息或者一个Type对象,而C++中可以通过type_if操作符获得一个type_info对象。
三关键字与语法结构
3.1 volatile关键字
volatile关键字在C#中表示字段可能被多个并发执行线程修改。声明为 volatile 的字段不受编译器优化(假定由单个线程访问)的限制。这样可以确保该字段在任何时间呈现的都是最新的值。在C++中用于表示变量可能随时会发生变法,这种变化有可能是由硬件操作导致的,这样也是为了避免编译器进行优化,以便随时获得最新的值。
3.2 static关键字
在C++中,static 可以用于声明函数中的变量,使其存储为静态存储;而在C#中static仅能声明类级别视体或者类的成员。
[C#]
public virtual void Test()
{
static
int i = 0;
}
编译器会报错。
[C++]
void CB::test(CA& a) const
{
static int j=100;}
在C++中允许。
另外static在C++在还可以改变文件变量的可访问性,加上static仅当前文档范围可以访问。
C++中的类的static成员与C#还有一点不同,即所有实例对象均可访问静态成员。
3.3 extern关键字
在C# 中,extern 修饰符用于声明在外部实现的方法。extern 修饰符的常见用法是在使用 Interop 服务调入非托管代码时与 DllImport 属性一起使用;在这种情况下,该方法还必须声明为 static,如下面的示例所示:
[DllImport("avifil32.dll")] private static extern void AVIFileInit();
而在C++ 中,extern关键字用于引进外部的变量,由于在C#中不存在全局变量,因此无此用法。
3.4全局变量与全局方法
在C#中无全局变量和全局方法,方法与变量必须位于类或者结构中;C++中拥有全局变量和全局方法,全局变量存储于静态存储中。
3.5头文件与宏
C#中不包含宏,而在C++中可以使用宏来替代特定的字符,比如圆周率等等。C#不使用头文件,方法的操作需要类来实现,而C++可以使用头文件,以便不同文件使用相同的方法而不会产生编译错误。
[C++]
#pragma once#include "targetver.h"#include <stdio.h>
#include <tchar.h>
#include <iostream>
3.6命名空间与using关键字
在C#中命名空间必须有名称,而C++可以不包括名称的命名空间,主要是为了限制变量的访问权限,同时namespace可以直接包含变量和方法的定义,而C#中只能包含类或者结构,接口,委托的定义等。
[C++]
namespace test{namespace { int counts; // static storage, internal linkage } int other(); int main() { } int other() { }}
using 在C#中可以导入命名空间下所有类型,而在C++中using可以直接在函数中使用,用于导入某一个对象。
[C++]
int _tmain(int argc, _TCHAR* argv[])
{
using std::cout;
cout<<"test";}
using在C++中还可以在多继承中使用此关键字重用父类中的方法。
[C++]
using BaseClass::Method;pDerivedClass->Method();
3.7构造函数
在C#中,值类型必须拥有默认构造函数,且初始化所有的值字段;在C++中如果没有构造函数,编译器会自动添加构造函数,且什么都不做,如果需要用到数组,类必须添加默认构造函数,否则会报错。
3.8复制构造函数
在对象按照值传递的时候,C#和C++都会复制一个对象,但是都是进行潜复制。在C++中,如果没有默认的复制构造函数,那么编译器会自动添加,将所有成员的值复制给新的对象,如果是指针,仅复制指针变量的值,而非其所指对象的值。在C#中没有复制构造函数,因此需要自己手动添加方法复制,如实现IClonable接口。
[C++]
baseDMA::baseDMA(const baseDMA & rs) baseBaseClass(rs){ label = new char[strlen(rs.label) + 1]; strcpy(label, rs.label); rating = rs.rating; }
3.9析构函数
C#和C++都拥有析构函数。
在C#中析构函数具有以下特点:
- 不能在结构中定义析构函数。只能对类使用析构函数。
- 一个类只能有一个析构函数。
- 无法继承或重载析构函数。
- 无法调用析构函数。它们是被自动调用的。
- 析构函数既没有修饰符,也没有参数。
在C#中,析构函数是垃圾回收器自动调用的,可以通过调用 Collect 强制进行垃圾回收,但大多数情况下应避免这样做,因为这样会导致性能问题。析构函数隐式调用
[C#]
class Car{ ~Car() // destructor { // cleanup statements... }}
该析构函数隐式地对对象的基类调用 Finalize。这样,前面的析构函数代码被隐式地转换为以下代码:
protected override void Finalize(){ try { // Cleanup statements... } finally { base.Finalize(); }}
在C++中析构函数一般我们用于释放动态分配的内存也就是通过new new[]分配的内存,可以通过delete delete[]来进行相应的清除。
3.10异常处理
在C#与C++中都有try{}catch{}的结构,而C#在此基础上新增了finally模块。
3.11按值与按引用传递
在C# 中,值类型默认按值传递,引用类型按照引用传递。也可以通过ref或者out使得值类型按照引用方式传递。值类型在传递的时候是开辟一个新的内存空间,复制现有的值,这样速度不快而且很浪费空间。
在C++中没有值类型和引用类型的概念,只有对象存储空间的区别,可以通过指针按照引用传递,或者通过type& 按引用类型传递。按引用传递与指针传递的一个不同的区别是,引用仅仅是一个别称而已,仅能在定义的时候对其进行赋值操作,而指针指向的地址可以随时更改。
[C#]
public override void Test()
{
int i;
if(Test(out i))
{
Console.WriteLine(i);
}
} public bool Test(out int i)
{
i = 0;
return true;
}
[C++]
void testArrayPointer()
{ int arr[3][4]={{1,2,3,4},{11,22,33,44},{111,222,333,444}};
int *p;
for(p=&arr[0][0];p<*arr+12;p++)
{
cout<<*(p)<<endl;
}
p=*arr;
for(p=arr[0];p<*arr+12;p++)
{
cout<<*(p)<<endl;
}
p=arr[0];
for(p=*(arr);p<*arr+12;p++)
{
cout<<*(p)<<endl;
} int (*p2)[4],i,j;
p2=arr;
for(i=0;i<3;i++)
{
for(j=0;j<4;j++)
{
cout<<*(*(p2+i)+j)<<" ";
}
cout<<endl;
}
}
3.12模板与泛型
C#中的泛型类似于C++中的模板,尽管两者在实现上有一定的区别。
3.13其他
当然C#本身还有很多其他的特性,比如foreach语句,readonly关键字,操作符重载与C++也有所不同,这里不再叙述。如果大家有很重要的特性的区别,可以回复,以便我增加到本文中。