C/C++与C#不同点对比分析总结
insights Stats
- 一数据结构与数据类型
- 1.1指针
- 1.2数组
- 1.3 Bool类型
- 1.4 long 类型
- 1.5函数指针与委托
- 1.6值类型与引用类型以及内存分配
- 1.7字符串
- 1.8位段与共同体union
- 二面向对象
- 2.1接口
- 2.2多重继承
- 2.3方法重载
- 2.4 friend与私有字段访问
- 2.5 RTTI运行时信息与cast
- 三关键字与语法结构
- 3.1 volatile关键字
- 3.2 static关键字
- 3.3 extern关键字
- 3.4全局变量与全局方法
- 3.5头文件与宏
- 3.6命名空间与using关键字
- 3.7构造函数
- 3.8复制构造函数
- 3.9析构函数
- 3.10异常处理
- 3.11按值与按引用传递
- 3.12模板与泛型
- 3.13其他
一数据结构与数据类型
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++也有所不同,这里不再叙述。如果大家有很重要的特性的区别,可以回复,以便我增加到本文中。