百度站长反馈中心,通辽网站建设招聘,c2c的网站名称和网址,做网站服务器的配置#x1f680; 优质资源分享 #x1f680;
学习路线指引#xff08;点击解锁#xff09;知识定位人群定位#x1f9e1; Python实战微信订餐小程序 #x1f9e1;进阶级本课程是python flask微信小程序的完美结合#xff0c;从项目搭建到腾讯云部署上线#xff0c;打造一… 优质资源分享
学习路线指引点击解锁知识定位人群定位 Python实战微信订餐小程序 进阶级本课程是python flask微信小程序的完美结合从项目搭建到腾讯云部署上线打造一个全栈订餐系统。Python量化交易实战入门级手把手带你打造一个易扩展、更安全、效率更高的量化交易系统
一背景
在 C# 中要说类默认给我们定义的特殊成员函数莫过于 构造函数但在 C 中这样的特殊函数高达 6 种有必要整合一下聊一聊。
二特殊成员函数
1. 默认构造函数
和 C# 一样很多书中都说如果用户没有定义 构造函数那么编译器会给我们定义一个参考下面的例子 class Person {public:string name;int age;
};int main()
{Person person;
}
接下来观察下汇编代码看下有没有调用 默认构造函数 .
Person person;
003E32EF lea ecx,[person]
003E32F2 call Person::Person (03E15EBh)
对于 C# 学习者来说有点懵哈定义了就相当于new了 哈哈这是因为 C 默认都是值类型哈不过这里有必要澄清一下并不一定所有情况都会调用 默认构造函数因为 C 的汇编生成由各自 编译器 来决定如果 编译器 觉得没必要调用 构造函数 那它就会把这一步省掉来加速性能那什么时候不会调呢 参考如下代码。 class Person {public:void show() {printf(show!);}
};int main()
{Person person;person.show();
}
接下来看下汇编代码。
person.show();
00E73F4F lea ecx,[person]
00E73F52 call Person::show (0E713B6h)
可以清楚的看到这种情况下调用 构造函数 其实没有必要所以编译器就干脆省略了。
2. 析构函数
在 C# 中 析构函数 是由 CLR 负责管理在 C 中没有托管这个概念所以默认只能是结束作用域之前自动调用 析构函数 释放参考如下图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t90ftep9-1657600937158)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/63cc8aea628345de9df318465a48bad7~tplv-k3u1fbpfcp-zoom-1.image)]
3. 赋值构造函数
刚才也说到了在 C 中甭管是 class 还是 struct 默认都是值类型既然是值类型就存在stack copy 的情况在 C# 中也是因为重写了 Equals 和 GetHashCode 来实现的值copy接下来简单看下代码 class Person {public:string name;int age;
};int main()
{Person p1 { jack,20 };Person p2(p1);
}
再看下 Person p2(p1) 的汇编代码。
Person p2(p1);
000F80A2 lea eax,[p1]
000F80A5 push eax
000F80A6 lea ecx,[p2]
000F80A9 call Person::Person (0F15C3h)
从汇编中可以看到调用了 Person::Person (0F15C3h) 函数请注意这个不是 构造函数而是 赋值构造函数 可以调试下去看看哦。。。 截图如下
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BKhIIeZq-1657600937162)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/915f1e7a804840cdbe630324ef226747~tplv-k3u1fbpfcp-zoom-1.image)]
值得说一下的是C 默认提供的 赋值构造函数 是浅copy如果要实现深 copy 的话或者有一些自定义的逻辑建议自己实现一下。 class Person {public:string name;int age;public:Person(string name, int age) :name(name), age(age) {}Person(const Person p) {name p.name;age p.age;}
};int main()
{Person p1 { aaaaaaaaaaaaaaaaaaaaaaaaaaa,20 };Person p2(p1);
}
4. 赋值运算符
在 C# 中 值类型 , 匿名类型, Record 都是重写过 Equals 及 运算符所以可以在这些类型上用 , 其实在 C 中也可以在 class 之间进行赋值因为编译器会帮我们重写运算符 如何看出来呢先看下代码 class Person {public:string name;int age;public:Person(string name, int age) :name(name), age(age) {}Person(const Person p) {name p.name;age p.age;}
};int main()
{Person p1 { aaaaaaaaaaaaaaaaaaaaaaaaaaa,20 };Person p2 { bbbbbbbbbbbbbbbbbbbbbbbbbbb,22 };p2 p1;
}
最后一句的 p2 p1 之所以能成功是因为 被重写了参考汇编代码。
p2 p1;
00FD967C lea eax,[p1]
00FD967F push eax
00FD9680 lea ecx,[p2]
00FD9683 call Person::operator (0FD161Dh)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xjf1b1OF-1657600937163)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d0a342b8fa824e3fa337e548be5b5db5~tplv-k3u1fbpfcp-zoom-1.image)]
如果需要自定义可以自己重写。 class Person {public:string name;int age;public:Person(string name, int age) :name(name), age(age) {}Person(const Person p) {name p.name;age p.age;}Person operator (const Person p) {name p.name;age p.age;return *this;}
};int main()
{Person p1 { aaaaaaaaaaaaaaaaaaaaaaaaaaa,20 };Person p2 { bbbbbbbbbbbbbbbbbbbbbbbbbbb,22 };p2 p1;
}
在 C 11 中还有特殊的 移动构造函数 和 移动赋值构造函数, 这个还需要理解 左值 和 右值引用篇幅有限放到后面和大家聊了哈。