C/C++与C#不同点对比分析总结

314 views 0 comments posted at about 6 years ago Raymond Tang Fahao

一数据结构与数据类型

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++也有所不同,这里不再叙述。如果大家有很重要的特性的区别,可以回复,以便我增加到本文中。

Add comment

Comments (0)

No comments yet.
In this Page