💡 关于
📚 本仓库是é¢å‘ C/C++ æŠ€æœ¯æ–¹å‘æ ¡æ‹›æ±‚èŒè€…ã€åˆå¦è€…的基础知识总结,包括è¯è¨€ã€ç¨‹åºåº“ã€æ•°æ®ç»“æž„ã€ç®—法ã€ç³»ç»Ÿã€ç½‘络ã€é“¾æŽ¥è£…载库ç‰çŸ¥è¯†åŠé¢è¯•ç»éªŒã€æ‹›è˜ã€å†…推ç‰ä¿¡æ¯ã€‚
💡 ä¾§è¾¹ç›®å½•æ”¯æŒæ–¹å¼ï¼šðŸ“š Docsify 文档ã€Github + TOC 导航(TOC预览.png)
📄 ä¿å˜ä¸º PDF æ–¹å¼ï¼šä½¿ç”¨ Chrome æµè§ˆå™¨æ‰“å¼€ 📚 Docsify 文档 页é¢ï¼Œç¼©èµ·å·¦ä¾§ç›®å½•-å³é”® - æ‰“å° - é€‰æ‹©ç›®æ ‡æ‰“å°æœºæ˜¯å¦å˜ä¸ºPDF - ä¿å˜ï¼ˆæ‰“å°é¢„览.png)
🙠仓库内容如有错误或改进欢迎 issue 或 pr,建议或讨论å¯åœ¨ #12 æå‡ºã€‚由于本人水平有é™ï¼Œä»“库ä¸çš„知识点有æ¥è‡ªæœ¬äººåŽŸåˆ›ã€è¯»ä¹¦ç¬”è®°ã€ä¹¦ç±ã€åšæ–‡ç‰ï¼ŒéžåŽŸåˆ›å‡å·²æ ‡æ˜Žå‡ºå¤„ï¼Œå¦‚æœ‰é—æ¼ï¼Œè¯· issue æå‡ºã€‚本仓库éµå¾ª CC BY-NC-SA 4.0(署å - éžå•†ä¸šæ€§ä½¿ç”¨ - ç›¸åŒæ–¹å¼å…±äº«ï¼‰ å议,转载请注明出处,ä¸å¾—用于商业目的。
- âž• C/C++
- âï¸ Effective
- 📦 STL
- ã€½ï¸ æ•°æ®ç»“æž„
- âš¡ï¸ ç®—æ³•
- â“ Problems
- 💻 æ“作系统
- â˜ï¸ 计算机网络
- 🌩 网络编程
- 💾 æ•°æ®åº“
- 📠设计模å¼
- âš™ï¸ é“¾æŽ¥è£…è½½åº“
- 📚 书ç±
- 🔱 C/C++ å‘展方å‘
- 💯 å¤ä¹ 刷题网站
- 📠é¢è¯•题目ç»éªŒ
- 📆 æ‹›è˜æ—¶é—´å²—ä½
- 👠内推
- 👬 贡献者
- 📜 License
- 修饰å˜é‡ï¼Œè¯´æ˜Žè¯¥å˜é‡ä¸å¯ä»¥è¢«æ”¹å˜ï¼›
- 修饰指针,分为指å‘常é‡çš„æŒ‡é’ˆï¼ˆpointer to const)和自身是常é‡çš„æŒ‡é’ˆï¼ˆå¸¸é‡æŒ‡é’ˆï¼Œconst pointer);
- 修饰引用,指å‘常é‡çš„引用(reference to const),用于形å‚类型,å³é¿å…了拷è´ï¼Œåˆé¿å…了函数对值的修改;
- 修饰æˆå‘˜å‡½æ•°ï¼Œè¯´æ˜Žè¯¥æˆå‘˜å‡½æ•°å†…ä¸èƒ½ä¿®æ”¹æˆå‘˜å˜é‡ã€‚
- 指针
- 指å‘常é‡çš„æŒ‡é’ˆï¼ˆpointer to const)
- 自身是常é‡çš„æŒ‡é’ˆï¼ˆå¸¸é‡æŒ‡é’ˆï¼Œconst pointer)
- 引用
- 指å‘常é‡çš„引用(reference to const)
- 没有 const referenceï¼Œå› ä¸ºå¼•ç”¨åªæ˜¯å¯¹è±¡çš„别åï¼Œå¼•ç”¨ä¸æ˜¯å¯¹è±¡ï¼Œä¸èƒ½ç”¨ const 修饰
(为了方便记忆å¯ä»¥æƒ³æˆï¼‰è¢« const 修饰(在 const åŽé¢ï¼‰çš„值ä¸å¯æ”¹å˜ï¼Œå¦‚下文使用例åä¸çš„
p2
ã€p3
const 使用
// ç±»
class A
{
private:
const int a; // 常对象æˆå‘˜ï¼Œå¯ä»¥ä½¿ç”¨åˆå§‹åŒ–列表或者类内åˆå§‹åŒ–
public:
// æž„é€ å‡½æ•°
A() : a(0) { };
A(int x) : a(x) { }; // åˆå§‹åŒ–列表
// constå¯ç”¨äºŽå¯¹é‡è½½å‡½æ•°çš„区分
int getValue(); // 普通æˆå‘˜å‡½æ•°
int getValue() const; // 常æˆå‘˜å‡½æ•°ï¼Œä¸å¾—修改类ä¸çš„ä»»ä½•æ•°æ®æˆå‘˜çš„值
};
void function()
{
// 对象
A b; // 普通对象,å¯ä»¥è°ƒç”¨å…¨éƒ¨æˆå‘˜å‡½æ•°
const A a; // 常对象,åªèƒ½è°ƒç”¨å¸¸æˆå‘˜å‡½æ•°
const A *p = &a; // 指针å˜é‡ï¼ŒæŒ‡å‘常对象
const A &q = a; // 指å‘常对象的引用
// 指针
char greeting[] = "Hello";
char* p1 = greeting; // 指针å˜é‡ï¼ŒæŒ‡å‘å—符数组å˜é‡
const char* p2 = greeting; // 指针å˜é‡ï¼ŒæŒ‡å‘å—符数组常é‡ï¼ˆconst åŽé¢æ˜¯ char,说明指å‘çš„å—符(char)ä¸å¯æ”¹å˜ï¼‰
char* const p3 = greeting; // 自身是常é‡çš„æŒ‡é’ˆï¼ŒæŒ‡å‘å—符数组å˜é‡ï¼ˆconst åŽé¢æ˜¯ p3,说明 p3 指针自身ä¸å¯æ”¹å˜ï¼‰
const char* const p4 = greeting; // 自身是常é‡çš„æŒ‡é’ˆï¼ŒæŒ‡å‘å—符数组常é‡
}
// 函数
void function1(const int Var); // ä¼ é€’è¿‡æ¥çš„傿•°åœ¨å‡½æ•°å†…ä¸å¯å˜
void function2(const char* Var); // 傿•°æŒ‡é’ˆæ‰€æŒ‡å†…容为常é‡
void function3(char* const Var); // 傿•°æŒ‡é’ˆä¸ºå¸¸é‡
void function4(const int& Var); // å¼•ç”¨å‚æ•°åœ¨å‡½æ•°å†…为常é‡
// 函数返回值
const int function5(); // 返回一个常数
const int* function6(); // 返回一个指å‘常é‡çš„æŒ‡é’ˆå˜é‡ï¼Œä½¿ç”¨ï¼šconst int *p = function6();
int* const function7(); // 返回一个指å‘å˜é‡çš„常指针,使用:int* const p = function7();
å®å®šä¹‰ #define | const å¸¸é‡ |
---|---|
å®å®šä¹‰ï¼Œç›¸å½“于å—ç¬¦æ›¿æ¢ | 常é‡å£°æ˜Ž |
预处ç†å™¨å¤„ç† | ç¼–è¯‘å™¨å¤„ç† |
æ— ç±»åž‹å®‰å…¨æ£€æŸ¥ | 有类型安全检查 |
ä¸åˆ†é…å†…å˜ | è¦åˆ†é…å†…å˜ |
å˜å‚¨åœ¨ä»£ç 段 | å˜å‚¨åœ¨æ•°æ®æ®µ |
å¯é€šè¿‡ #undef å–æ¶ˆ |
ä¸å¯å–消 |
- 修饰普通å˜é‡ï¼Œä¿®æ”¹å˜é‡çš„å˜å‚¨åŒºåŸŸå’Œç”Ÿå‘½å‘¨æœŸï¼Œä½¿å˜é‡å˜å‚¨åœ¨é™æ€åŒºï¼Œåœ¨ main 函数è¿è¡Œå‰å°±åˆ†é…了空间,如果有åˆå§‹å€¼å°±ç”¨åˆå§‹å€¼åˆå§‹åŒ–它,如果没有åˆå§‹å€¼ç³»ç»Ÿç”¨é»˜è®¤å€¼åˆå§‹åŒ–它。
- 修饰普通函数,表明函数的作用范围,仅在定义该函数的文件内æ‰èƒ½ä½¿ç”¨ã€‚在多人开å‘项目时,为了防æ¢ä¸Žä»–人命å空间里的函数é‡å,å¯ä»¥å°†å‡½æ•°å®šä½ä¸º static。
- 修饰æˆå‘˜å˜é‡ï¼Œä¿®é¥°æˆå‘˜å˜é‡ä½¿æ‰€æœ‰çš„对象åªä¿å˜ä¸€ä¸ªè¯¥å˜é‡ï¼Œè€Œä¸”ä¸éœ€è¦ç”Ÿæˆå¯¹è±¡å°±å¯ä»¥è®¿é—®è¯¥æˆå‘˜ã€‚
- 修饰æˆå‘˜å‡½æ•°ï¼Œä¿®é¥°æˆå‘˜å‡½æ•°ä½¿å¾—ä¸éœ€è¦ç”Ÿæˆå¯¹è±¡å°±å¯ä»¥è®¿é—®è¯¥å‡½æ•°ï¼Œä½†æ˜¯åœ¨ static 函数内ä¸èƒ½è®¿é—®éžé™æ€æˆå‘˜ã€‚
this
指针是一个éšå«äºŽæ¯ä¸€ä¸ªéžé™æ€æˆå‘˜å‡½æ•°ä¸çš„特殊指针。它指å‘调用该æˆå‘˜å‡½æ•°çš„那个对象。- 当对一个对象调用æˆå‘˜å‡½æ•°æ—¶ï¼Œç¼–译程åºå…ˆå°†å¯¹è±¡çš„地å€èµ‹ç»™
this
指针,然åŽè°ƒç”¨æˆå‘˜å‡½æ•°ï¼Œæ¯æ¬¡æˆå‘˜å‡½æ•°å˜å–æ•°æ®æˆå‘˜æ—¶ï¼Œéƒ½éšå¼ä½¿ç”¨this
指针。 - 当一个æˆå‘˜å‡½æ•°è¢«è°ƒç”¨æ—¶ï¼Œè‡ªåЍå‘å®ƒä¼ é€’ä¸€ä¸ªéšå«çš„傿•°ï¼Œè¯¥å‚数是一个指å‘这个æˆå‘˜å‡½æ•°æ‰€åœ¨çš„对象的指针。
this
指针被éšå«åœ°å£°æ˜Žä¸º:ClassName *const this
,这æ„味ç€ä¸èƒ½ç»™this
指针赋值;在ClassName
类的const
æˆå‘˜å‡½æ•°ä¸ï¼Œthis
指针的类型为:const ClassName* const
,这说明ä¸èƒ½å¯¹this
指针所指å‘的这ç§å¯¹è±¡æ˜¯ä¸å¯ä¿®æ”¹çš„(å³ä¸èƒ½å¯¹è¿™ç§å¯¹è±¡çš„æ•°æ®æˆå‘˜è¿›è¡Œèµ‹å€¼æ“作);this
并䏿˜¯ä¸€ä¸ªå¸¸è§„å˜é‡ï¼Œè€Œæ˜¯ä¸ªå³å€¼ï¼Œæ‰€ä»¥ä¸èƒ½å–å¾—this
的地å€ï¼ˆä¸èƒ½&this
)。- 在以下场景ä¸ï¼Œç»å¸¸éœ€è¦æ˜¾å¼å¼•用
this
指针:- 为实现对象的链å¼å¼•用;
- 为é¿å…对åŒä¸€å¯¹è±¡è¿›è¡Œèµ‹å€¼æ“作;
- 在实现一些数æ®ç»“构时,如
list
。
- 相当于把内è”函数里é¢çš„内容写在调用内è”函数处;
- 相当于ä¸ç”¨æ‰§è¡Œè¿›å…¥å‡½æ•°çš„æ¥éª¤ï¼Œç›´æŽ¥æ‰§è¡Œå‡½æ•°ä½“ï¼›
- 相当于å®ï¼Œå´æ¯”å®å¤šäº†ç±»åž‹æ£€æŸ¥ï¼ŒçœŸæ£å…·æœ‰å‡½æ•°ç‰¹æ€§ï¼›
- 编译器一般ä¸å†…è”包å«å¾ªçޝã€é€’å½’ã€switch ç‰å¤æ‚æ“作的内è”函数;
- 在类声明ä¸å®šä¹‰çš„函数,除了虚函数的其他函数都会自动éšå¼åœ°å½“æˆå†…è”函数。
inline 使用
// 声明1ï¼ˆåŠ inline,建议使用)
inline int functionName(int first, int second,...);
// 声明2(ä¸åŠ inline)
int functionName(int first, int second,...);
// 定义
inline int functionName(int first, int second,...) {/****/};
// 类内定义,éšå¼å†…è”
class A {
int doA() { return 0; } // éšå¼å†…è”
}
// ç±»å¤–å®šä¹‰ï¼Œéœ€è¦æ˜¾å¼å†…è”
class A {
int doA();
}
inline int A::doA() { return 0; } // éœ€è¦æ˜¾å¼å†…è”
- å°† inline 函数体å¤åˆ¶åˆ° inline 函数调用点处;
- 为所用 inline 函数ä¸çš„局部å˜é‡åˆ†é…内å˜ç©ºé—´ï¼›
- å°† inline å‡½æ•°çš„çš„è¾“å…¥å‚æ•°å’Œè¿”å›žå€¼æ˜ å°„åˆ°è°ƒç”¨æ–¹æ³•çš„å±€éƒ¨å˜é‡ç©ºé—´ä¸ï¼›
- 如果 inline 函数有多个返回点,将其转å˜ä¸º inline 函数代ç å—æœ«å°¾çš„分支(使用 GOTO)。
优点
- 内è”函数åŒå®å‡½æ•°ä¸€æ ·å°†åœ¨è¢«è°ƒç”¨å¤„进行代ç 展开,çœåŽ»äº†å‚æ•°åŽ‹æ ˆã€æ ˆå¸§å¼€è¾Ÿä¸Žå›žæ”¶ï¼Œç»“果返回ç‰ï¼Œä»Žè€Œæé«˜ç¨‹åºè¿è¡Œé€Ÿåº¦ã€‚
- 内è”函数相比å®å‡½æ•°æ¥è¯´ï¼Œåœ¨ä»£ç 展开时,会åšå®‰å…¨æ£€æŸ¥æˆ–自动类型转æ¢ï¼ˆåŒæ™®é€šå‡½æ•°ï¼‰ï¼Œè€Œå®å®šä¹‰åˆ™ä¸ä¼šã€‚
- 在类ä¸å£°æ˜ŽåŒæ—¶å®šä¹‰çš„æˆå‘˜å‡½æ•°ï¼Œè‡ªåŠ¨è½¬åŒ–ä¸ºå†…è”å‡½æ•°ï¼Œå› æ¤å†…è”函数å¯ä»¥è®¿é—®ç±»çš„æˆå‘˜å˜é‡ï¼Œå®å®šä¹‰åˆ™ä¸èƒ½ã€‚
- 内è”函数在è¿è¡Œæ—¶å¯è°ƒè¯•,而å®å®šä¹‰ä¸å¯ä»¥ã€‚
缺点
- 代ç è†¨èƒ€ã€‚å†…è”æ˜¯ä»¥ä»£ç 膨胀(å¤åˆ¶ï¼‰ä¸ºä»£ä»·ï¼Œæ¶ˆé™¤å‡½æ•°è°ƒç”¨å¸¦æ¥çš„开销。如果执行函数体内代ç 的时间,相比于函数调用的开销较大,那么效率的收获会很少。å¦ä¸€æ–¹é¢ï¼Œæ¯ä¸€å¤„内è”函数的调用都è¦å¤åˆ¶ä»£ç ,将使程åºçš„æ€»ä»£ç é‡å¢žå¤§ï¼Œæ¶ˆè€—更多的内å˜ç©ºé—´ã€‚
- inline å‡½æ•°æ— æ³•éšç€å‡½æ•°åº“å‡çº§è€Œå‡çº§ã€‚inline函数的改å˜éœ€è¦é‡æ–°ç¼–译,ä¸åƒ non-inline å¯ä»¥ç›´æŽ¥é“¾æŽ¥ã€‚
- 是å¦å†…è”,程åºå‘˜ä¸å¯æŽ§ã€‚内è”å‡½æ•°åªæ˜¯å¯¹ç¼–译器的建议,是å¦å¯¹å‡½æ•°å†…è”,决定æƒåœ¨äºŽç¼–译器。
Are "inline virtual" member functions ever actually "inlined"?
- 虚函数å¯ä»¥æ˜¯å†…è”å‡½æ•°ï¼Œå†…è”æ˜¯å¯ä»¥ä¿®é¥°è™šå‡½æ•°çš„ï¼Œä½†æ˜¯å½“è™šå‡½æ•°è¡¨çŽ°å¤šæ€æ€§çš„æ—¶å€™ä¸èƒ½å†…è”。
- å†…è”æ˜¯åœ¨ç¼–译期建议编译器内è”ï¼Œè€Œè™šå‡½æ•°çš„å¤šæ€æ€§åœ¨è¿è¡ŒæœŸï¼Œç¼–è¯‘å™¨æ— æ³•çŸ¥é“è¿è¡ŒæœŸè°ƒç”¨å“ªä¸ªä»£ç ï¼Œå› æ¤è™šå‡½æ•°è¡¨çŽ°ä¸ºå¤šæ€æ€§æ—¶ï¼ˆè¿è¡ŒæœŸï¼‰ä¸å¯ä»¥å†…è”。
inline virtual
唯一å¯ä»¥å†…è”çš„æ—¶å€™æ˜¯ï¼šç¼–è¯‘å™¨çŸ¥é“æ‰€è°ƒç”¨çš„对象是哪个类(如Base::who()
ï¼‰ï¼Œè¿™åªæœ‰åœ¨ç¼–è¯‘å™¨å…·æœ‰å®žé™…å¯¹è±¡è€Œä¸æ˜¯å¯¹è±¡çš„æŒ‡é’ˆæˆ–引用时æ‰ä¼šå‘生。
虚函数内è”使用
#include <iostream>
using namespace std;
class Base
{
public:
inline virtual void who()
{
cout << "I am Base\n";
}
virtual ~Base() {}
};
class Derived : public Base
{
public:
inline void who() // ä¸å†™inlineæ—¶éšå¼å†…è”
{
cout << "I am Derived\n";
}
};
int main()
{
// æ¤å¤„的虚函数 who(),是通过类(Base)的具体对象(b)æ¥è°ƒç”¨çš„,编译期间就能确定了,所以它å¯ä»¥æ˜¯å†…è”的,但最终是å¦å†…è”å–决于编译器。
Base b;
b.who();
// æ¤å¤„çš„è™šå‡½æ•°æ˜¯é€šè¿‡æŒ‡é’ˆè°ƒç”¨çš„ï¼Œå‘ˆçŽ°å¤šæ€æ€§ï¼Œéœ€è¦åœ¨è¿è¡Œæ—¶æœŸé—´æ‰èƒ½ç¡®å®šï¼Œæ‰€ä»¥ä¸èƒ½ä¸ºå†…è”。
Base *ptr = new Derived();
ptr->who();
// å› ä¸ºBaseæœ‰è™šæžæž„函数(virtual ~Base() {}),所以 delete 时,会先调用派生类(Derivedï¼‰æžæž„函数,å†è°ƒç”¨åŸºç±»ï¼ˆBaseï¼‰æžæž„函数,防æ¢å†…å˜æ³„æ¼ã€‚
delete ptr;
ptr = nullptr;
system("pause");
return 0;
}
volatile int i = 10;
- volatile 关键嗿˜¯ä¸€ç§ç±»åž‹ä¿®é¥°ç¬¦ï¼Œç”¨å®ƒå£°æ˜Žçš„类型å˜é‡è¡¨ç¤ºå¯ä»¥è¢«æŸäº›ç¼–è¯‘å™¨æœªçŸ¥çš„å› ç´ ï¼ˆæ“作系统ã€ç¡¬ä»¶ã€å…¶å®ƒçº¿ç¨‹ç‰ï¼‰æ›´æ”¹ã€‚所以使用 volatile 告诉编译器ä¸åº”å¯¹è¿™æ ·çš„å¯¹è±¡è¿›è¡Œä¼˜åŒ–ã€‚
- volatile 关键å—声明的å˜é‡ï¼Œæ¯æ¬¡è®¿é—®æ—¶éƒ½å¿…须从内å˜ä¸å–出值(没有被 volatile 修饰的å˜é‡ï¼Œå¯èƒ½ç”±äºŽç¼–译器的优化,从 CPU 寄å˜å™¨ä¸å–值) A92E
- const å¯ä»¥æ˜¯ volatile (如åªè¯»çš„状æ€å¯„å˜å™¨ï¼‰
- 指针å¯ä»¥æ˜¯ volatile
æ–言,是å®ï¼Œè€Œéžå‡½æ•°ã€‚assert å®çš„原型定义在 <assert.h>
(C)ã€<cassert>
(C++)ä¸ï¼Œå…¶ä½œç”¨æ˜¯å¦‚果它的æ¡ä»¶è¿”回错误,则终æ¢ç¨‹åºæ‰§è¡Œã€‚å¯ä»¥é€šè¿‡å®šä¹‰ NDEBUG
æ¥å…³é— assert,但是需è¦åœ¨æºä»£ç 的开头,include <assert.h>
之å‰ã€‚
assert() 使用
#define NDEBUG // åŠ ä¸Šè¿™è¡Œï¼Œåˆ™ assert ä¸å¯ç”¨
#include <assert.h>
assert( p != NULL ); // assert ä¸å¯ç”¨
- sizeof 对数组,得到整个数组所å 空间大å°ã€‚
- sizeof 对指针,得到指针本身所å 空间大å°ã€‚
设定结构体ã€è”åˆä»¥åŠç±»æˆå‘˜å˜é‡ä»¥ n å—节方å¼å¯¹é½
#pragma pack(n) 使用
#pragma pack(push) // ä¿å˜å¯¹é½çжæ€
#pragma pack(4) // 设定为 4 å—节对é½
struct test
{
char m1;
double m4;
int m3;
};
#pragma pack(pop) // æ¢å¤å¯¹é½çжæ€
Bit mode: 2; // mode å 2 ä½
ç±»å¯ä»¥å°†å…¶ï¼ˆéžé™æ€ï¼‰æ•°æ®æˆå‘˜å®šä¹‰ä¸ºä½åŸŸï¼ˆbit-field),在一个ä½åŸŸä¸å«æœ‰ä¸€å®šæ•°é‡çš„二进制ä½ã€‚当一个程åºéœ€è¦å‘å…¶ä»–ç¨‹åºæˆ–ç¡¬ä»¶è®¾å¤‡ä¼ é€’äºŒè¿›åˆ¶æ•°æ®æ—¶ï¼Œé€šå¸¸ä¼šç”¨åˆ°ä½åŸŸã€‚
- ä½åŸŸåœ¨å†…å˜ä¸çš„布局是与机器有关的
- ä½åŸŸçš„类型必须是整型或枚举类型,带符å·ç±»åž‹ä¸çš„ä½åŸŸçš„è¡Œä¸ºå°†å› å…·ä½“å®žçŽ°è€Œå®š
- å–地å€è¿ç®—符(&)ä¸èƒ½ä½œç”¨äºŽä½åŸŸï¼Œä»»ä½•æŒ‡é’ˆéƒ½æ— æ³•æŒ‡å‘类的ä½åŸŸ
- 被 extern é™å®šçš„函数或å˜é‡æ˜¯ extern 类型的
- 被
extern "C"
修饰的å˜é‡å’Œå‡½æ•°æ˜¯æŒ‰ç…§ C è¯è¨€æ–¹å¼ç¼–译和链接的
extern "C"
的作用是让 C++ 编译器将 extern "C"
声明的代ç 当作 C è¯è¨€ä»£ç 处ç†ï¼Œå¯ä»¥é¿å… C++ å› ç¬¦å·ä¿®é¥°å¯¼è‡´ä»£ç ä¸èƒ½å’ŒCè¯è¨€åº“ä¸çš„符å·è¿›è¡Œé“¾æŽ¥çš„问题。
extern "C" 使用
#ifdef __cplusplus
extern "C" {
#endif
void *memset(void *, int, size_t);
#ifdef __cplusplus
}
#endif
// c
typedef struct Student {
int age;
} S;
ç‰ä»·äºŽ
// c
struct Student {
int age;
};
typedef struct Student S;
æ¤æ—¶ S
ç‰ä»·äºŽ struct Student
ï¼Œä½†ä¸¤ä¸ªæ ‡è¯†ç¬¦å称空间ä¸ç›¸åŒã€‚
å¦å¤–还å¯ä»¥å®šä¹‰ä¸Ž struct Student
ä¸å†²çªçš„ void Student() {}
。
由于编译器定ä½ç¬¦å·çš„规则(æœç´¢è§„则)改å˜ï¼Œå¯¼è‡´ä¸åŒäºŽCè¯è¨€ã€‚
一ã€å¦‚æžœåœ¨ç±»æ ‡è¯†ç¬¦ç©ºé—´å®šä¹‰äº† struct Student {...};
,使用 Student me;
时,编译器将æœç´¢å…¨å±€æ ‡è¯†ç¬¦è¡¨ï¼ŒStudent
æœªæ‰¾åˆ°ï¼Œåˆ™åœ¨ç±»æ ‡è¯†ç¬¦å†…æœç´¢ã€‚
å³è¡¨çŽ°ä¸ºå¯ä»¥ä½¿ç”¨ Student
也å¯ä»¥ä½¿ç”¨ struct Student
,如下:
// cpp
struct Student {
int age;
};
void f( Student me ); // æ£ç¡®ï¼Œ"struct" 关键å—å¯çœç•¥
二ã€è‹¥å®šä¹‰äº†ä¸Ž Student
åŒå函数之åŽï¼Œåˆ™ Student
åªä»£è¡¨å‡½æ•°ï¼Œä¸ä»£è¡¨ç»“构体,如下:
typedef struct Student {
int age;
} S;
void Student() {} // æ£ç¡®ï¼Œå®šä¹‰åŽ "Student" åªä»£è¡¨æ¤å‡½æ•°
//void S() {} // é”™è¯¯ï¼Œç¬¦å· "S" å·²ç»è¢«å®šä¹‰ä¸ºä¸€ä¸ª "struct Student" 的别å
int main() {
Student();
struct Student me; // 或者 "S me";
return 0;
}
总的æ¥è¯´ï¼Œstruct 更适åˆçœ‹æˆæ˜¯ä¸€ä¸ªæ•°æ®ç»“构的实现体,class 更适åˆçœ‹æˆæ˜¯ä¸€ä¸ªå¯¹è±¡çš„实现体。
- 最本质的一个区别就是默认的访问控制
- 默认的继承访问æƒé™ã€‚struct 是 public 的,class 是 private 的。
- struct 作为数æ®ç»“构的实现体,它默认的数æ®è®¿é—®æŽ§åˆ¶æ˜¯ public 的,而 class 作为对象的实现体,它默认的æˆå‘˜å˜é‡è®¿é—®æŽ§åˆ¶æ˜¯ private 的。
è”åˆï¼ˆunion)是一ç§èŠ‚çœç©ºé—´çš„特殊的类,一个 union å¯ä»¥æœ‰å¤šä¸ªæ•°æ®æˆå‘˜ï¼Œä½†æ˜¯åœ¨ä»»æ„æ—¶åˆ»åªæœ‰ä¸€ä¸ªæ•°æ®æˆå‘˜å¯ä»¥æœ‰å€¼ã€‚当æŸä¸ªæˆå‘˜è¢«èµ‹å€¼åŽå…¶ä»–æˆå‘˜å˜ä¸ºæœªå®šä¹‰çжæ€ã€‚è”åˆæœ‰å¦‚下特点:
- 默认访问控制符为 public
- å¯ä»¥å«æœ‰æž„é€ å‡½æ•°ã€æžæž„函数
- ä¸èƒ½å«æœ‰å¼•用类型的æˆå‘˜
- ä¸èƒ½ç»§æ‰¿è‡ªå…¶ä»–类,ä¸èƒ½ä½œä¸ºåŸºç±»
- ä¸èƒ½å«æœ‰è™šå‡½æ•°
- 匿å union 在定义所在作用域å¯ç›´æŽ¥è®¿é—® union æˆå‘˜
- 匿å union ä¸èƒ½åŒ…å« protected æˆå‘˜æˆ– private æˆå‘˜
- 全局匿åè”åˆå¿…é¡»æ˜¯é™æ€ï¼ˆstatic)的
union 使用
#include<iostream>
union UnionTest {
UnionTest() : i(10) {};
int i;
double d;
};
static union {
int i;
double d;
};
int main() {
UnionTest u;
union {
int i;
double d;
};
std::cout << u.i << std::endl; // 输出 UnionTest è”åˆçš„ 10
::i = 20;
std::cout << ::i << std::endl; // è¾“å‡ºå…¨å±€é™æ€åŒ¿åè”åˆçš„ 20
i = 30;
std::cout << i << std::endl; // 输出局部匿åè”åˆçš„ 30
return 0;
}
C 实现 C++ çš„é¢å‘对象特性(å°è£…ã€ç»§æ‰¿ã€å¤šæ€ï¼‰
- å°è£…:使用函数指针把属性与方法å°è£…到结构体ä¸
- 继承:结构体嵌套
- 多æ€ï¼šçˆ¶ç±»ä¸Žå类方法的函数指针ä¸åŒ
- explicit ä¿®é¥°æž„é€ å‡½æ•°æ—¶ï¼Œå¯ä»¥é˜²æ¢éšå¼è½¬æ¢å’Œå¤åˆ¶åˆå§‹åŒ–
- explicit 修饰转æ¢å‡½æ•°æ—¶ï¼Œå¯ä»¥é˜²æ¢éšå¼è½¬æ¢ï¼Œä½† 按è¯å¢ƒè½¬æ¢ 除外
explicit 使用
struct A
{
A(int) { }
operator bool() const { return true; }
};
struct B
{
explicit B(int) {}
explicit operator bool() const { return true; }
};
void doA(A a) {}
void doB(B b) {}
int main()
{
A a1(1); // OK:直接åˆå§‹åŒ–
A a2 = 1; // OK:å¤åˆ¶åˆå§‹åŒ–
A a3{ 1 }; // OK:直接列表åˆå§‹åŒ–
A a4 = { 1 }; // OK:å¤åˆ¶åˆ—表åˆå§‹åŒ–
A a5 = (A)1; // OK:å…许 static_cast 的显å¼è½¬æ¢
doA(1); // OK:å…许从 int 到 A çš„éšå¼è½¬æ¢
if (a1); // OK:使用转æ¢å‡½æ•° A::operator bool() 的从 A 到 bool çš„éšå¼è½¬æ¢
bool a6(a1); // OK:使用转æ¢å‡½æ•° A::operator bool() 的从 A 到 bool çš„éšå¼è½¬æ¢
bool a7 = a1; // OK:使用转æ¢å‡½æ•° A::operator bool() 的从 A 到 bool çš„éšå¼è½¬æ¢
bool a8 = static_cast<bool>(a1); // OK :static_cast 进行直接åˆå§‹åŒ–
B b1(1); // OK:直接åˆå§‹åŒ–
B b2 = 1; // 错误:被 explicit ä¿®é¥°æž„é€ å‡½æ•°çš„å¯¹è±¡ä¸å¯ä»¥å¤åˆ¶åˆå§‹åŒ–
B b3{ 1 }; // OK:直接列表åˆå§‹åŒ–
B b4 = { 1 }; // 错误:被 explicit ä¿®é¥°æž„é€ å‡½æ•°çš„å¯¹è±¡ä¸å¯ä»¥å¤åˆ¶åˆ—表åˆå§‹åŒ–
B b5 = (B)1; // OK:å…许 static_cast 的显å¼è½¬æ¢
doB(1); // 错误:被 explicit ä¿®é¥°æž„é€ å‡½æ•°çš„å¯¹è±¡ä¸å¯ä»¥ä»Ž int 到 B çš„éšå¼è½¬æ¢
if (b1); // OK:被 explicit 修饰转æ¢å‡½æ•° B::operator bool() 的对象å¯ä»¥ä»Ž B 到 bool 的按è¯å¢ƒè½¬æ¢
bool b6(b1); // OK:被 explicit 修饰转æ¢å‡½æ•° B::operator bool() 的对象å¯ä»¥ä»Ž B 到 bool 的按è¯å¢ƒè½¬æ¢
bool b7 = b1; // 错误:被 explicit 修饰转æ¢å‡½æ•° B::operator bool() 的对象ä¸å¯ä»¥éšå¼è½¬æ¢
bool b8 = static_cast<bool>(b1); // OK:static_cast 进行直接åˆå§‹åŒ–
return 0;
}
- èƒ½è®¿é—®ç§æœ‰æˆå‘˜
- ç ´åå°è£…性
- å‹å…ƒå…³ç³»ä¸å¯ä¼ 递
- å‹å…ƒå…³ç³»çš„å•呿€§
- å‹å…ƒå£°æ˜Žçš„å½¢å¼åŠæ•°é‡ä¸å—é™åˆ¶
ä¸€æ¡ using 声明
è¯å¥ä¸€æ¬¡åªå¼•入命å空间的一个æˆå‘˜ã€‚它使得我们å¯ä»¥æ¸…楚知é“程åºä¸æ‰€å¼•用的到底是哪个åå—。如:
using namespace_name::name;
在 C++11 ä¸ï¼Œæ´¾ç”Ÿç±»èƒ½å¤Ÿé‡ç”¨å…¶ç›´æŽ¥åŸºç±»å®šä¹‰çš„æž„é€ å‡½æ•°ã€‚
class Derived : Base {
public:
using Base::Base;
/* ... */
};
如上 using 声明,对于基类的æ¯ä¸ªæž„é€ å‡½æ•°ï¼Œç¼–è¯‘å™¨éƒ½ç”Ÿæˆä¸€ä¸ªä¸Žä¹‹å¯¹åº”(形å‚列表完全相åŒï¼‰çš„æ´¾ç”Ÿç±»æž„é€ å‡½æ•°ã€‚ç”Ÿæˆå¦‚ä¸‹ç±»åž‹æž„é€ å‡½æ•°ï¼š
Derived(parms) : Base(args) { }
using 指示
使得æŸä¸ªç‰¹å®šå‘½åç©ºé—´ä¸æ‰€æœ‰åå—都å¯è§ï¼Œè¿™æ ·æˆ‘ä»¬å°±æ— éœ€å†ä¸ºå®ƒä»¬æ·»åР任何å‰ç¼€é™å®šç¬¦äº†ã€‚如:
using namespace_name name;
一般说æ¥ï¼Œä½¿ç”¨ using 命令比使用 using 编译命令更安全,这是由于它åªå¯¼å…¥äº†æŒ‡å®šçš„å称。如果该å称与局部åç§°å‘生冲çªï¼Œç¼–译器将å‘出指示。using编译命令导入所有的å称,包括å¯èƒ½å¹¶ä¸éœ€è¦çš„å称。如果与局部åç§°å‘生冲çªï¼Œåˆ™å±€éƒ¨å称将覆盖å称空间版本,而编译器并ä¸ä¼šå‘出è¦å‘Šã€‚å¦å¤–,å称空间的开放性æ„味ç€å称空间的åç§°å¯èƒ½åˆ†æ•£åœ¨å¤šä¸ªåœ°æ–¹ï¼Œè¿™ä½¿å¾—éš¾ä»¥å‡†ç¡®çŸ¥é“æ·»åŠ äº†å“ªäº›å称。
using 使用
å°½é‡å°‘使用 using 指示
using namespace std;
应该多使用 using 声明
int x;
std::cin >> x ;
std::cout << x << std::endl;
或者
using std::cin;
using std::cout;
using std::endl;
int x;
cin >> x;
cout << x << endl;
- 全局作用域符(
::name
):用于类型å称(类ã€ç±»æˆå‘˜ã€æˆå‘˜å‡½æ•°ã€å˜é‡ç‰ï¼‰å‰ï¼Œè¡¨ç¤ºä½œç”¨åŸŸä¸ºå…¨å±€å‘½å空间 - 类作用域符(
class::name
):用于表示指定类型的作用域范围是具体æŸä¸ªç±»çš„ - 命å空间作用域符(
namespace::name
):用于表示指定类型的作用域范围是具体æŸä¸ªå‘½å空间的
:: 使用
int count = 11; // 全局(::)的 count
class A {
public:
static int count; // 类 A 的 count(A::count)
};
int A::count = 21;
void fun()
{
int count = 31; // åˆå§‹åŒ–局部的 count 为 31
count = 32; // 设置局部的 count 的值为 32
}
int main() {
::count = 12; // 测试 1:设置全局的 count 的值为 12
A::count = 22; // 测试 2:设置类 A 的 count 为 22
fun(); // 测试 3
return 0;
}
enum class open_modes { input, output, append };
enum color { red, yellow, green };
enum { floatPrec = 6, doublePrec = 10 };
decltype 关键å—用于检查实体的声明类型或表达å¼çš„类型åŠå€¼åˆ†ç±»ã€‚è¯æ³•:
decltype ( expression )
decltype 使用
// 尾置返回å…è®¸æˆ‘ä»¬åœ¨å‚æ•°åˆ—表之åŽå£°æ˜Žè¿”回类型
template <typename It>
auto fcn(It beg, It end) -> decltype(*beg)
{
// 处ç†åºåˆ—
return *beg; // 返回åºåˆ—ä¸ä¸€ä¸ªå…ƒç´ 的引用
}
// 为了使用模æ¿å‚æ•°æˆå‘˜ï¼Œå¿…须用 typename
template <typename It>
auto fcn2(It beg, It end) -> typename remove_reference<decltype(*beg)>::type
{
// 处ç†åºåˆ—
return *beg; // 返回åºåˆ—ä¸ä¸€ä¸ªå…ƒç´ 的拷è´
}
常规引用,一般表示对象的身份。
å³å€¼å¼•用就是必须绑定到å³å€¼ï¼ˆä¸€ä¸ªä¸´æ—¶å¯¹è±¡ã€å°†è¦é”€æ¯çš„对象)的引用,一般表示对象的值。
å³å€¼å¼•用å¯å®žçŽ°è½¬ç§»è¯ä¹‰ï¼ˆMove Sementicsï¼‰å’Œç²¾ç¡®ä¼ é€’ï¼ˆPerfect Forwarding),它的主è¦ç›®çš„æœ‰ä¸¤ä¸ªæ–¹é¢ï¼š
- 消除两个对象交互时ä¸å¿…è¦çš„对象拷è´ï¼ŒèŠ‚çœè¿ç®—å˜å‚¨èµ„æºï¼Œæé«˜æ•ˆçŽ‡ã€‚
- èƒ½å¤Ÿæ›´ç®€æ´æ˜Žç¡®åœ°å®šä¹‰æ³›åž‹å‡½æ•°ã€‚
X& &
ã€X& &&
ã€X&& &
å¯æŠ˜å æˆX&
X&& &&
å¯æŠ˜å æˆX&&
- å®å®šä¹‰å¯ä»¥å®žçŽ°ç±»ä¼¼äºŽå‡½æ•°çš„åŠŸèƒ½ï¼Œä½†æ˜¯å®ƒç»ˆå½’ä¸æ˜¯å‡½æ•°ï¼Œè€Œå®å®šä¹‰ä¸æ‹¬å¼§ä¸çš„â€œå‚æ•°â€ä¹Ÿä¸æ˜¯çœŸçš„傿•°ï¼Œåœ¨å®å±•开的时候对 â€œå‚æ•°â€ 进行的是一对一的替æ¢ã€‚
好处
- æ›´é«˜æ•ˆï¼šå°‘äº†ä¸€æ¬¡è°ƒç”¨é»˜è®¤æž„é€ å‡½æ•°çš„è¿‡ç¨‹ã€‚
- 有些场åˆå¿…é¡»è¦ç”¨åˆå§‹åŒ–列表:
- 叏釿ˆå‘˜ï¼Œå› 为常é‡åªèƒ½åˆå§‹åŒ–ä¸èƒ½èµ‹å€¼ï¼Œæ‰€ä»¥å¿…须放在åˆå§‹åŒ–列表里é¢
- 引用类型,引用必须在定义的时候åˆå§‹åŒ–,并且ä¸èƒ½é‡æ–°èµ‹å€¼ï¼Œæ‰€ä»¥ä¹Ÿè¦å†™åœ¨åˆå§‹åŒ–列表里é¢
- æ²¡æœ‰é»˜è®¤æž„é€ å‡½æ•°çš„ç±»ç±»åž‹ï¼Œå› ä¸ºä½¿ç”¨åˆå§‹åŒ–列表å¯ä»¥ä¸å¿…è°ƒç”¨é»˜è®¤æž„é€ å‡½æ•°æ¥åˆå§‹åŒ–
用花括å·åˆå§‹åŒ–器列表åˆå§‹åŒ–一个对象,其ä¸å¯¹åº”æž„é€ å‡½æ•°æŽ¥å—一个 std::initializer_list
傿•°.
initializer_list 使用
#include <iostream>
#include <vector>
#include <initializer_list>
template <class T>
struct S {
std::vector<T> v;
S(std::initializer_list<T> l) : v(l) {
std::cout << "constructed with a " << l.size() << "-element list\n";
}
void append(std::initializer_list<T> l) {
v.insert(v.end(), l.begin(), l.end());
}
std::pair<const T*, std::size_t> c_arr() const {
return {&v[0], v.size()}; // 在 return è¯å¥ä¸å¤åˆ¶åˆ—表åˆå§‹åŒ–
// è¿™ä¸ä½¿ç”¨ std::initializer_list
}
};
template <typename T>
void templated_fn(T) {}
int main()
{
S<int> s = {1, 2, 3, 4, 5}; // å¤åˆ¶åˆå§‹åŒ–
s.append({6, 7, 8}); // 函数调用ä¸çš„列表åˆå§‹åŒ–
std::cout << "The vector size is now " << s.c_arr().second << " ints:\n";
for (auto n : s.v)
std::cout << n << ' ';
std::cout << '\n';
std::cout << "Range-for over brace-init-list: \n";
for (int x : {-1, -2, -3}) // auto 的规则令æ¤å¸¦èŒƒå›´ for 工作
std::cout << x << ' ';
std::cout << '\n';
auto al = {10, 11, 12}; // auto 的特殊规则
std::cout << "The list bound to auto has size() = " << al.size() << '\n';
// templated_fn({1, 2, 3}); // 编译错误ï¼â€œ {1, 2, 3} â€ä¸æ˜¯è¡¨è¾¾å¼ï¼Œ
// å®ƒæ— ç±»åž‹ï¼Œæ•… T æ— æ³•æŽ¨å¯¼
templated_fn<std::initializer_list<int>>({1, 2, 3}); // OK
templated_fn<std::vector<int>>({1, 2, 3}); // 也 OK
}
é¢å‘对象程åºè®¾è®¡ï¼ˆObject-oriented programming,OOP)是ç§å…·æœ‰å¯¹è±¡æ¦‚念的程åºç¼–ç¨‹å…¸èŒƒï¼ŒåŒæ—¶ä¹Ÿæ˜¯ä¸€ç§ç¨‹åºå¼€å‘的抽象方针。
é¢å‘å¯¹è±¡ä¸‰å¤§ç‰¹å¾ â€”â€” å°è£…ã€ç»§æ‰¿ã€å¤šæ€
把客观事物å°è£…æˆæŠ½è±¡çš„ç±»ï¼Œå¹¶ä¸”ç±»å¯ä»¥æŠŠè‡ªå·±çš„æ•°æ®å’Œæ–¹æ³•åªè®©å¯ä¿¡çš„类或者对象æ“作,对ä¸å¯ä¿¡çš„进行信æ¯éšè—。关键å—:public, protected, private。ä¸å†™é»˜è®¤ä¸º private。
public
æˆå‘˜ï¼šå¯ä»¥è¢«ä»»æ„实体访问protected
æˆå‘˜ï¼šåªå…许被åç±»åŠæœ¬ç±»çš„æˆå‘˜å‡½æ•°è®¿é—®private
æˆå‘˜ï¼šåªå…许被本类的æˆå‘˜å‡½æ•°ã€å‹å…ƒç±»æˆ–å‹å…ƒå‡½æ•°è®¿é—®
- 基类(父类)——> 派生类(å类)
- 多æ€ï¼Œå³å¤šç§çжæ€ï¼ˆå½¢æ€ï¼‰ã€‚ç®€å•æ¥è¯´ï¼Œæˆ‘们å¯ä»¥å°†å¤šæ€å®šä¹‰ä¸ºæ¶ˆæ¯ä»¥å¤šç§å½¢å¼æ˜¾ç¤ºçš„能力。
- å¤šæ€æ˜¯ä»¥å°è£…和继承为基础的。
- C++ 多æ€åˆ†ç±»åŠå®žçŽ°ï¼š
- é‡è½½å¤šæ€ï¼ˆAd-hoc Polymorphism,编译期):函数é‡è½½ã€è¿ç®—符é‡è½½
- å类型多æ€ï¼ˆSubtype Polymorphism,è¿è¡ŒæœŸï¼‰ï¼šè™šå‡½æ•°
- 傿•°å¤šæ€æ€§ï¼ˆParametric Polymorphism,编译期):类模æ¿ã€å‡½æ•°æ¨¡æ¿
- 强制多æ€ï¼ˆCoercion Polymorphism,编译期/è¿è¡ŒæœŸï¼‰ï¼šåŸºæœ¬ç±»åž‹è½¬æ¢ã€è‡ªå®šä¹‰ç±»åž‹è½¬æ¢
函数é‡è½½
class A
{
public:
void do(int a);
void do(int a, int b);
};
- 虚函数:用 virtual 修饰æˆå‘˜å‡½æ•°ï¼Œä½¿å…¶æˆä¸ºè™šå‡½æ•°
- 动æ€ç»‘定:当使用基类的引用或指针调用一个虚函数时将å‘生动æ€ç»‘定
注æ„:
- å¯ä»¥å°†æ´¾ç”Ÿç±»çš„对象赋值给基类的指针或引用,å之ä¸å¯
- 普通函数(éžç±»æˆå‘˜å‡½æ•°ï¼‰ä¸èƒ½æ˜¯è™šå‡½æ•°
- 陿€å‡½æ•°ï¼ˆstatic)ä¸èƒ½æ˜¯è™šå‡½æ•°
- æž„é€ å‡½æ•°ä¸èƒ½æ˜¯è™šå‡½æ•°ï¼ˆå› ä¸ºåœ¨è°ƒç”¨æž„é€ å‡½æ•°æ—¶ï¼Œè™šè¡¨æŒ‡é’ˆå¹¶æ²¡æœ‰åœ¨å¯¹è±¡çš„å†…å˜ç©ºé—´ä¸ï¼Œå¿…é¡»è¦æž„é€ å‡½æ•°è°ƒç”¨å®ŒæˆåŽæ‰ä¼šå½¢æˆè™šè¡¨æŒ‡é’ˆï¼‰
- 内è”函数ä¸èƒ½æ˜¯è¡¨çŽ°å¤šæ€æ€§æ—¶çš„虚函数,解释è§ï¼šè™šå‡½æ•°ï¼ˆvirtual)å¯ä»¥æ˜¯å†…è”函数(inline)å—?
动æ€å¤šæ€ä½¿ç”¨
class Shape // 形状类
{
public:
virtual double calcArea()
{
...
}
virtual ~Shape();
};
class Circle : public Shape // 圆形类
{
public:
virtual double calcArea();
...
};
class Rect : public Shape // 矩形类
{
public:
virtual double calcArea();
...
};
int main()
{
Shape * shape1 = new Circle(4.0);
Shape * shape2 = new Rect(5.0, 6.0);
shape1->calcArea(); // 调用圆形类里é¢çš„æ–¹æ³•
shape2->calcArea(); // 调用矩形类里é¢çš„æ–¹æ³•
delete shape1;
shape1 = nullptr;
delete shape2;
shape2 = nullptr;
return 0;
}
è™šæžæž„å‡½æ•°æ˜¯ä¸ºäº†è§£å†³åŸºç±»çš„æŒ‡é’ˆæŒ‡å‘æ´¾ç”Ÿç±»å¯¹è±¡ï¼Œå¹¶ç”¨åŸºç±»çš„æŒ‡é’ˆåˆ 除派生类对象。
è™šæžæž„函数使用
class Shape
{
public:
Shape(); // æž„é€ å‡½æ•°ä¸èƒ½æ˜¯è™šå‡½æ•°
virtual double calcArea();
virtual ~Shape(); // è™šæžæž„函数
};
class Circle : public Shape // 圆形类
{
public:
virtual double calcArea();
...
};
int main()
{
Shape * shape1 = new Circle(4.0);
shape1->calcArea();
delete shape1; // å› ä¸ºShapeæœ‰è™šæžæž„函数,所以deleteé‡Šæ”¾å†…å˜æ—¶ï¼Œå…ˆè°ƒç”¨åç±»æžæž„函数,å†è°ƒç”¨åŸºç±»æžæž„函数,防æ¢å†…å˜æ³„æ¼ã€‚
shape1 = NULL;
return 0ï¼›
}
纯虚函数是一ç§ç‰¹æ®Šçš„虚函数,在基类ä¸ä¸èƒ½å¯¹è™šå‡½æ•°ç»™å‡ºæœ‰æ„义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去åšã€‚
virtual int A() = 0;
- 类里如果声明了虚函数,这个函数是实现的,哪怕是空实现,它的作用就是为了能让这个函数在它的å类里é¢å¯ä»¥è¢«è¦†ç›–(overrideï¼‰ï¼Œè¿™æ ·çš„è¯ï¼Œç¼–译器就å¯ä»¥ä½¿ç”¨åŽæœŸç»‘定æ¥è¾¾åˆ°å¤šæ€äº†ã€‚çº¯è™šå‡½æ•°åªæ˜¯ä¸€ä¸ªæŽ¥å£ï¼Œæ˜¯ä¸ªå‡½æ•°çš„声明而已,它è¦ç•™åˆ°å类里去实现。
- 虚函数在å类里é¢å¯ä»¥ä¸é‡å†™ï¼›ä½†çº¯è™šå‡½æ•°å¿…须在å类实现æ‰å¯ä»¥å®žä¾‹åŒ–å类。
- 虚函数的类用于 “实作继承â€ï¼Œç»§æ‰¿æŽ¥å£çš„åŒæ—¶ä¹Ÿç»§æ‰¿äº†çˆ¶ç±»çš„实现。纯虚函数关注的是接å£çš„统一性,实现由å类完æˆã€‚
- å¸¦çº¯è™šå‡½æ•°çš„ç±»å«æŠ½è±¡ç±»ï¼Œè¿™ç§ç±»ä¸èƒ½ç›´æŽ¥ç”Ÿæˆå¯¹è±¡ï¼Œè€Œåªæœ‰è¢«ç»§æ‰¿ï¼Œå¹¶é‡å†™å…¶è™šå‡½æ•°åŽï¼Œæ‰èƒ½ä½¿ç”¨ã€‚抽象类被继承åŽï¼Œåç±»å¯ä»¥ç»§ç»æ˜¯æŠ½è±¡ç±»ï¼Œä¹Ÿå¯ä»¥æ˜¯æ™®é€šç±»ã€‚
- 虚基类是虚继承ä¸çš„基类,具体è§ä¸‹æ–‡è™šç»§æ‰¿ã€‚
- è™šå‡½æ•°æŒ‡é’ˆï¼šåœ¨å«æœ‰è™šå‡½æ•°ç±»çš„对象ä¸ï¼ŒæŒ‡å‘虚函数表,在è¿è¡Œæ—¶ç¡®å®šã€‚
- 虚函数表:在程åºåªè¯»æ•°æ®æ®µï¼ˆ
.rodata section
,è§ï¼šç›®æ ‡æ–‡ä»¶å˜å‚¨ç»“æž„ï¼‰ï¼Œå˜æ”¾è™šå‡½æ•°æŒ‡é’ˆï¼Œå¦‚果派生类实现了基类的æŸä¸ªè™šå‡½æ•°ï¼Œåˆ™åœ¨è™šè¡¨ä¸è¦†ç›–åŽŸæœ¬åŸºç±»çš„é‚£ä¸ªè™šå‡½æ•°æŒ‡é’ˆï¼Œåœ¨ç¼–è¯‘æ—¶æ ¹æ®ç±»çš„声明创建。
C++ä¸çš„虚函数(表)实现机制以åŠç”¨Cè¯è¨€å¯¹å…¶è¿›è¡Œçš„æ¨¡æ‹Ÿå®žçް
虚继承用于解决多继承æ¡ä»¶ä¸‹çš„è±å½¢ç»§æ‰¿é—®é¢˜ï¼ˆæµªè´¹å˜å‚¨ç©ºé—´ã€å˜åœ¨äºŒä¹‰æ€§ï¼‰ã€‚
底层实现原ç†ä¸Žç¼–译器相关,一般通过虚基类指针和虚基类表实现,æ¯ä¸ªè™šç»§æ‰¿çš„å类都有一个虚基类指针(å 用一个指针的å˜å‚¨ç©ºé—´ï¼Œ4å—节)和虚基类表(ä¸å 用类对象的å˜å‚¨ç©ºé—´ï¼‰ï¼ˆéœ€è¦å¼ºè°ƒçš„æ˜¯ï¼Œè™šåŸºç±»ä¾æ—§ä¼šåœ¨å类里é¢å˜åœ¨æ‹·è´ï¼Œåªæ˜¯ä»…仅最多å˜åœ¨ä¸€ä»½è€Œå·²ï¼Œå¹¶ä¸æ˜¯ä¸åœ¨å类里é¢äº†ï¼‰ï¼›å½“虚继承的å类被当åšçˆ¶ç±»ç»§æ‰¿æ—¶ï¼Œè™šåŸºç±»æŒ‡é’ˆä¹Ÿä¼šè¢«ç»§æ‰¿ã€‚
实际上,vbptr 指的是虚基类表指针(virtual base table pointer),该指针指å‘了一个虚基类表(virtual table),虚表ä¸è®°å½•了虚基类与本类的å移地å€ï¼›é€šè¿‡å移地å€ï¼Œè¿™æ ·å°±æ‰¾åˆ°äº†è™šåŸºç±»æˆå‘˜ï¼Œè€Œè™šç»§æ‰¿ä¹Ÿä¸ç”¨åƒæ™®é€šå¤šç»§æ‰¿é‚£æ ·ç»´æŒç€å…¬å…±åŸºç±»ï¼ˆè™šåŸºç±»ï¼‰çš„ä¸¤ä»½åŒæ ·çš„æ‹·è´ï¼ŒèŠ‚çœäº†å˜å‚¨ç©ºé—´ã€‚
- 相åŒä¹‹å¤„:都利用了虚指针(å‡å 用类的å˜å‚¨ç©ºé—´ï¼‰å’Œè™šè¡¨ï¼ˆå‡ä¸å 用类的å˜å‚¨ç©ºé—´ï¼‰
- ä¸åŒä¹‹å¤„:
- 虚继承
- è™šåŸºç±»ä¾æ—§å˜åœ¨ç»§æ‰¿ç±»ä¸ï¼Œåªå 用å˜å‚¨ç©ºé—´
- 虚基类表å˜å‚¨çš„æ˜¯è™šåŸºç±»ç›¸å¯¹ç›´æŽ¥ç»§æ‰¿ç±»çš„åç§»
- 虚函数
- 虚函数ä¸å 用å˜å‚¨ç©ºé—´
- 虚函数表å˜å‚¨çš„æ˜¯è™šå‡½æ•°åœ°å€
- 虚继承
- 类模æ¿ä¸å¯ä»¥ä½¿ç”¨è™šå‡½æ•°
- ä¸€ä¸ªç±»ï¼ˆæ— è®ºæ˜¯æ™®é€šç±»è¿˜æ˜¯ç±»æ¨¡æ¿ï¼‰çš„æˆå‘˜æ¨¡æ¿ï¼ˆæœ¬èº«æ˜¯æ¨¡æ¿çš„æˆå‘˜å‡½æ•°ï¼‰ä¸èƒ½æ˜¯è™šå‡½æ•°
- æŠ½è±¡ç±»ï¼šå«æœ‰çº¯è™šå‡½æ•°çš„ç±»
- 接å£ç±»ï¼šä»…嫿œ‰çº¯è™šå‡½æ•°çš„æŠ½è±¡ç±»
- èšåˆç±»ï¼šç”¨æˆ·å¯ä»¥ç›´æŽ¥è®¿é—®å…¶æˆå‘˜ï¼Œå¹¶ä¸”具有特殊的åˆå§‹åŒ–è¯æ³•å½¢å¼ã€‚满足如下特点:
- 所有æˆå‘˜éƒ½æ˜¯ public
- æ²¡æœ‰å®šä¹‰ä»»ä½•æž„é€ å‡½æ•°
- 没有类内åˆå§‹åŒ–
- 没有基类,也没有 virtual 函数
- malloc:申请指定å—节数的内å˜ã€‚申请到的内å˜ä¸çš„åˆå§‹å€¼ä¸ç¡®å®šã€‚
- calloc:为指定长度的对象,分é…能容纳其指定个数的内å˜ã€‚申请到的内å˜çš„æ¯ä¸€ä½ï¼ˆbit)都åˆå§‹åŒ–为 0。
- realloc:更改以å‰åˆ†é…的内å˜é•¿åº¦ï¼ˆå¢žåŠ æˆ–å‡å°‘ï¼‰ã€‚å½“å¢žåŠ é•¿åº¦æ—¶ï¼Œå¯èƒ½éœ€å°†ä»¥å‰åˆ†é…区的内容移到å¦ä¸€ä¸ªè¶³å¤Ÿå¤§çš„区域,而新增区域内的åˆå§‹å€¼åˆ™ä¸ç¡®å®šã€‚
- allocaï¼šåœ¨æ ˆä¸Šç”³è¯·å†…å˜ã€‚程åºåœ¨å‡ºæ ˆçš„æ—¶å€™ï¼Œä¼šè‡ªåŠ¨é‡Šæ”¾å†…å˜ã€‚ä½†æ˜¯éœ€è¦æ³¨æ„的是,alloca ä¸å…·å¯ç§»æ¤æ€§, è€Œä¸”åœ¨æ²¡æœ‰ä¼ ç»Ÿå †æ ˆçš„æœºå™¨ä¸Šå¾ˆéš¾å®žçŽ°ã€‚alloca ä¸å®œä½¿ç”¨åœ¨å¿…须广泛移æ¤çš„程åºä¸ã€‚C99 䏿”¯æŒå˜é•¿æ•°ç»„ (VLA),å¯ä»¥ç”¨æ¥æ›¿ä»£ alloca。
用于分é…ã€é‡Šæ”¾å†…å˜
mallocã€free 使用
申请内å˜ï¼Œç¡®è®¤æ˜¯å¦ç”³è¯·æˆåŠŸ
char *str = (char*) malloc(100);
assert(str != nullptr);
释放内å˜åŽæŒ‡é’ˆç½®ç©º
free(p);
p = nullptr;
- new / new[]:完æˆä¸¤ä»¶äº‹ï¼Œå…ˆåº•层调用 malloc 分é…了内å˜ï¼Œç„¶åŽè°ƒç”¨æž„é€ å‡½æ•°ï¼ˆåˆ›å»ºå¯¹è±¡ï¼‰ã€‚
- delete/delete[]:也完æˆä¸¤ä»¶äº‹ï¼Œå…ˆè°ƒç”¨æžæž„函数(清ç†èµ„æºï¼‰ï¼Œç„¶åŽåº•层调用 free 释放空间。
- new åœ¨ç”³è¯·å†…å˜æ—¶ä¼šè‡ªåŠ¨è®¡ç®—æ‰€éœ€å—节数,而 malloc 则需我们自己输入申请内å˜ç©ºé—´çš„å—节数。
newã€delete 使用
申请内å˜ï¼Œç¡®è®¤æ˜¯å¦ç”³è¯·æˆåŠŸ
int main()
{
T* t = new T(); // 先内å˜åˆ†é… ï¼Œå†æž„é€ å‡½æ•°
delete t; // å…ˆæžæž„函数,å†å†…å˜é‡Šæ”¾
return 0;
}
å®šä½ new(placement new)å…è®¸æˆ‘ä»¬å‘ new ä¼ é€’é¢å¤–的地å€å‚数,从而在预先指定的内å˜åŒºåŸŸåˆ›å»ºå¯¹è±¡ã€‚
new (place_address) type
new (place_address) type (initializers)
new (place_address) type [size]
new (place_address) type [size] { braced initializer list }
place_address
是个指针initializers
æä¾›ä¸€ä¸ªï¼ˆå¯èƒ½ä¸ºç©ºçš„)以逗å·åˆ†éš”çš„åˆå§‹å€¼åˆ—表
Is it legal (and moral) for a member function to say delete this?
åˆæ³•,但:
- å¿…é¡»ä¿è¯ this 对象是通过
new
ï¼ˆä¸æ˜¯new[]
ã€ä¸æ˜¯ placement newã€ä¸æ˜¯æ ˆä¸Šã€ä¸æ˜¯å…¨å±€ã€ä¸æ˜¯å…¶ä»–对象æˆå‘˜ï¼‰åˆ†é…çš„ - å¿…é¡»ä¿è¯è°ƒç”¨
delete this
çš„æˆå‘˜å‡½æ•°æ˜¯æœ€åŽä¸€ä¸ªè°ƒç”¨ this çš„æˆå‘˜å‡½æ•° - å¿…é¡»ä¿è¯æˆå‘˜å‡½æ•°çš„
delete this
åŽé¢æ²¡æœ‰è°ƒç”¨ this 了 - å¿…é¡»ä¿è¯
delete this
åŽæ²¡æœ‰äººä½¿ç”¨äº†
如何定义一个åªèƒ½åœ¨å †ä¸Šï¼ˆæ ˆä¸Šï¼‰ç”Ÿæˆå¯¹è±¡çš„ç±»?
æ–¹æ³•ï¼šå°†æžæž„å‡½æ•°è®¾ç½®ä¸ºç§æœ‰
åŽŸå› ï¼šC++ æ˜¯é™æ€ç»‘定è¯è¨€ï¼Œç¼–è¯‘å™¨ç®¡ç†æ ˆä¸Šå¯¹è±¡çš„ç”Ÿå‘½å‘¨æœŸï¼Œç¼–è¯‘å™¨åœ¨ä¸ºç±»å¯¹è±¡åˆ†é…æ ˆç©ºé—´æ—¶ï¼Œä¼šå…ˆæ£€æŸ¥ç±»çš„æžæž„å‡½æ•°çš„è®¿é—®æ€§ã€‚è‹¥æžæž„函数ä¸å¯è®¿é—®ï¼Œåˆ™ä¸èƒ½åœ¨æ ˆä¸Šåˆ›å»ºå¯¹è±¡ã€‚
方法:将 new å’Œ delete é‡è½½ä¸ºç§æœ‰
åŽŸå› ï¼šåœ¨å †ä¸Šç”Ÿæˆå¯¹è±¡ï¼Œä½¿ç”¨ new å…³é”®è¯æ“作,其过程分为两阶段:第一阶段,使用 new åœ¨å †ä¸Šå¯»æ‰¾å¯ç”¨å†…å˜ï¼Œåˆ†é…ç»™å¯¹è±¡ï¼›ç¬¬äºŒé˜¶æ®µï¼Œè°ƒç”¨æž„é€ å‡½æ•°ç”Ÿæˆå¯¹è±¡ã€‚å°† new æ“ä½œè®¾ç½®ä¸ºç§æœ‰ï¼Œé‚£ä¹ˆç¬¬ä¸€é˜¶æ®µå°±æ— 法完æˆï¼Œå°±ä¸èƒ½å¤Ÿåœ¨å †ä¸Šç”Ÿæˆå¯¹è±¡ã€‚