在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
注:C#语言发展十分迅速,而且仍然有很大的提升空间,所以现在写下的有关C#语言上的一些限制,可能过一两年就不同了,所以需要不断更新。至于C++,因为已经很久没怎么变动,所以就容易得多。 (*) 允许初始化成员变量
(*) 编译器自动添加默认无参构造函数
(*) char和long的长度不同
(*) struct的内存分配不同 (*) 默认参数值
(*) 条件编译 C#里的#if比较全才,能代替C++中的#if, #ifdef, #ifndef C++:#ifdef DEBUG, #ifndef DEBUG C#:#if DEBUG, #if !DEBUG
(*) 设置按几字节对齐(pack)
#pragma pack(1) // modify
struct A { int i; char c; }; #pragma pack(4) // reset default 在C++里,一旦修改了pack后,就一直生效,直到再把它改回去。 C#:
[StructLayout(LayoutKind.Sequential, Pack=1)]
struct A { int i; char c; } 在c#里pack是作为struct的属性,所以不像c++那样一旦指定后面都生效,而是要为每个struct分别指定。
(*) sizeof (*) 多维数组
int** jagged = new int*[3];
for(int i = 0; i < 3; ++i) jagged[i] = new int[4]; for(int i = 0; i < 3; ++i) for(int j = 0; j < 4; ++j) jagged[i][j] = i * 4 + j; int *matrix = new int[3 * 4]; for(int i = 0; i < 3 * 4; ++i) matrix[i] = i;
int[][] jagged = new int[3][];
for (int i = 0; i < jagged.Length; i++) { jagged[i] = new int[4]; } for (int i = 0; i < jagged.Length; i++) { for (int j = 0; j < jagged[i].Length; j++) { jagged[i][j] = i * 4 + j; } } int[,] matrix = new int[3, 4]; for (int i = 0; i < matrix.Length; i++) { matrix[i/4, i%4] = i; // matrix[i] = i; Error in C# but OK in C++ }
(*) namespace C#
//可以这样:
namespace OuterNamespace { namespace InnerNamespace { class A { } } } //也可以这样(我更喜欢这样,因为这可以省掉很多缩进): namespace OuterNamespace.InnerNamespace { class B { } }
(*) 构造函数初始化列表 C++:既可以初始化该类本身,也可以初始化其基类的成员。 c#:只可以初始化其基类的成员 除了上面说的基类默认构造函数是private的情况,使用base(...)初始化父类成员也会提高效率,因为如果不使用,就会调用父类默认的构造函数,父类先被构造一遍,然后在子类的构造函数内部再给父类的成员赋值,可不就多余了。
(*) 多态的enable与disable enable多态 disable多态(子类向父类隐藏实现,有点像孩子瞒着家长) C++:无法实现 C# :用new关键字来取代override
(*) 抽象类与抽象(纯虚)函数
class A
{ public: virtual void foo()=0; void bar() { cout << "A::bar" << endl; } }; class B : public A { public: void foo() { cout << "B::foo" << endl; } }; int main() { B b; b.foo(); b.bar(); return 0; }
C#例子:
namespace ConsoleApplication1
{ abstract class A { abstract public void foo(); public void bar() { Console.WriteLine("A.bar"); } } class B : A { override public void foo() // override不能少,否则编译器会认为B没有实现A中的foo函数而报错 { Console.WriteLine("B.foo"); } } class Program { static void Main(string[] args) { B obj = new B(); obj.foo(); obj.bar(); } } }
(*) 类型转换 C# (*)全局变量
(*) 异常 C++ C#异常的补充: C# catch 或 C#异常的补充: 2.自定义异常的最佳实践 一般的应用程序异常应该继承自ApplicationException,而不是SystemException。这样可以很好地区分哪些异常是应用程序产生的,哪些是.NET底层类库产生的。所以一般简单的自定义的异常都这么写:
(*) 回调
class A
{ public: void foo() { cout << "foo" << endl; } void bar() { cout << "bar" << endl; } }; typedef void (A::*f)(void); void func(f fp) { A a; (a.*fp)(); } int main() { f fp = &A::foo; func(fp); fp = &A::bar; func(fp); return 0; } 从上面代码可以看出,在C++里实例的函数指针必须加上实例名做前缀。虽然号称是指向实例成员的函数指针,但也仅仅是个指针而已(vtbl中的偏移量),它对实例的状态一无所知。而C#就不同了。 C#:使用委托:对实例方法支持得更好,支持异步。 举一个C#中实例函数的委托的例子:
class MyClass
{ private string name; public MyClass(string name) { this.name = name; } public void DisplayName() { Console.WriteLine("{0}", name); } } class Program { // 委托其实就相当于一个类型。这里,类型的名字叫SimpleDelegate public delegate void SimpleDelegate(); static void Main() { MyClass a = new MyClass("A"); MyClass b = new MyClass("B"); // 用实例方法DisplayName初始化 SimpleDelegate d = new SimpleDelegate(a.DisplayName); d(); d = new SimpleDelegate(b.DisplayName); d(); } }
(*) 数组的创建 C++无论在堆上还是栈上创建数组,都是实实在在地分配内存,并对数组中的每一个元素调用构造函数。 C#则不一样。对值类型它分配内存并初始化成0,对引用类型则只给每个对象分配一个引用,并初始化成null。
MyClass[] classArray = new MyClass[1]; // No instance is created, classArray[0] is null
MyStruct[] structArray = new MyStruct[1]; // struct is created indeed, structArray[0] is an existing struct |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论