一数据结构与数据类型

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

About author
Disclaimer
The opinions and comments expressed herein are my own personal opinions and do not represent my employer's view in any way.
Comments
No comments.
Add comment
Title
Title is required.
Name
Name is required.
Email
Please input your personal email with valid format.
Comments
Please input comment content.
Captcha Refresh
Input captcha:

Subscription

Statistics

Locations of visitors to this page