引用
- 引用是C++语法做的优化,引用的本质还是靠指针来实现的。
- 引用相当于变量的别名。
- 引用可以改变指针的指向,还可以改变指针所指向的值。
引用的基本规则:
声明引用的时候必须初始化,且一旦绑定,不可把引用绑定到其他对象;即引用必须初始化,不能对引用重定义;
对引用的一切操作,就相当于对原对象的操作。
哪些地方可以引用?
- 引用可以作形参(解决了传值和传地址的问题) void swap(int &a, int &b);
- 做返回值(函数调用作返回值)
引用是否占用内存控件?
- 从使用角度—不占用;
- 从编译器----占用
指针和引用的区别? (面试题)
- 引用不可为空,指针可以为空。
- 指针在使用之前必须指向空,引用在声明的时候就必须初始化,指针可以改变指向,但是引用一旦初始化就不可解绑
左值引用和右值引用:
左值和右值:
- 左值:左值是可以放在赋值号左边可以被赋值的值;左值必须要在内存中有实体;
- 右值:右值当在赋值号右边取出值赋给其他变量的值;右值可以在内存也可以在CPU寄存器。
- 一个对象被用作右值时,使用的是它的内容(值),被当作左值时,使用的是它的地址。
左值引用和右值引用:
- 左值引用:左值引用的基本语法:type &引用名 = 左值表达式;
- 右值引用:右值引用的基本语法type &&引用名 = 右值表达式;
右值引用在企业开发人员在代码优化方面会经常用到。
右值引用的“&&”中间不可以有空格。
#include <iostream>
using namespace std;
int main()
{
cout << "-------引用左值--------" << endl;
int a = 5;
int &add_a(a);
cout << " a =" << a <<" "<<" &a = "<<&a<< endl;
cout << "add_a =" << add_a<<" "<< "&add_a = " << &add_a << endl;
cout << "-----------------------" << endl;
cout << "-------引用右值--------" << endl;
int b = 10;
int &&add_b(b + 1);
cout << " b =" << b << " " << " &b = " << &b << endl;
cout << "add_b =" << add_b << " " << "&add_b = " << &add_b << endl;
add_b++;
cout << "add_b++ =" << add_b << " " << "&add_b++ = " << &add_b << endl;
cout << "-----------------------" << endl;
system("pause");
return 0;
}
运行结果:

内联函数
- 定义: 当函数被声明为内联函数之后, 编译器会将其内联展开, 而不是按通常的函数调用机制进行调用.
- 优点: 当函数体比较小的时候, 内联该函数可以令目标代码更加高效. 对于存取函数以及其它函数体比较短, 性能关键的函数, 鼓励使用内联.
- 缺点: 滥用内联将导致程序变慢. 内联可能使目标代码量或增或减, 这取决于内联函数的大小. 内联非常短小的存取函数通常会减少代码大小, 但内联一个相当大的函数将戏剧性的增加代码大小. 现代处理器由于更好的利用了指令缓存, 小巧的代码往往执行更快。
- 结论: 一个较为合理的经验准则是, 不要内联超过 10 行的函数. 谨慎对待析构函数, 析构函数往往比其表面看起来要更长, 因为有隐含的成员和基类析构函数被调用!
为什么用内联函数?(一般慎用)
函数虽然有这么多好处,但是写成函数有一个潜在的缺点:调用函数比求解等价表达式要慢得多。在大多数的机器上,调用函数都要做很多工作:调用前要先保存寄存器,并在返回时恢复,复制实参,程序还必须转向一个新位置执行。
C++中支持内联函数,其目的是为了提高函数的执行效率,用关键字 inline 放在函数定义(注意是定义而非声明,下文继续讲到)的前面即可将函数指定为内联函数,内联函数通常就是将它在程序中的每个调用点上“内联地”展开,假设我们将 max 定义为内联函数:
inline int max(int a, int b)
{
return a > b ? a : b;
}
则调用: cout<<max(a, b)<<endl;
在编译时展开为: cout<<(a > b ? a : b)<<endl;
从而消除了把 max写成函数的额外执行开销
什么时候用内联函数?
- 只有当函数只有 10 行甚至更少时才将其定义为内联函数
内联函数的使用:
关键字 inline 必须与函数定义体放在一起才能使函数成为内联,仅将 inline 放在函数声明前面不起任何作用。
如下风格的函数 Foo 不能成为内联函数:
inline void Foo(int x, int y); // inline 仅与函数声明放在一起
void Foo(int x, int y)
{
...
}
而如下风格的函数 Foo 则成为内联函数:
void Foo(int x, int y);
inline void Foo(int x, int y) // inline 与函数定义体放在一起
{
...
}
所以说,C++ inline函数是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了 inline 关键字,但我认为 inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。
定义在类声明之中的成员函数将自动地成为内联函数,例如:
class A
{
public:
void Foo(int x, int y) { ... } // 自动地成为内联函数
}
但是编译器是否将它真正内联则要看 Foo函数如何定义
内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。
当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。
但是你会很奇怪,重复定义那么多次,不会产生链接错误?
我们来看一个例子:
A.h :
class A
{
public:
A(int a, int b) : a(a),b(b){}
int max();
private:
int a;
int b;
};
A.cpp:
#include "A.h"
inline int A::max()
{
return a > b ? a : b;
}
Main.cpp :
#include <iostream>
#include "A.h"
using namespace std;
inline int A::max()
{
return a > b ? a : b;
}
int main()
{
A a(3, 5);
cout<<a.max()<<endl;
return 0;
}
一切正常编译,输出结果:5
倘若你在Main.cpp中没有定义max内联函数,那么会出现链接错误:
error LNK2001: unresolved external symbol “public: int __thiscall A::max(void)” (?max@A@@QAEHXZ)main.obj
找不到函数的定义,所以内联函数可以在程序中定义不止一次,只要 inline 函数的定义在某个源文件中只出现一次,而且在所有源文件中,其定义必须是完全相同的就可以。
在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。
C++函数升级
struct升级
- 定义变量(结构体+变量名)struct Node;
- 结构体可以保存函数
- 结构体可以继承
- 结构体可以多态
- 结构体可以封装(权限修饰符private protected public)
- 结构体默认访问权限public private:不可被外部变量访问,只能结构体内部访问
class VS struct
- class默认权限是privat,而struct是public
- class类class定义的变量叫对象
- class内部保存的变量称之为属性或者成员变量
- class内部函数称之为方法
string类总结:
头文件:include
1.定义string:
#include <iostream>
#include <string>
using namespace std;
int main ( )
{
string str; //定义了一个空字符串str
str = "Hello world"; // 给str赋值为"Hello world"
char cstr[] = "abcde"; //定义了一个C字符串
string s1(str); //调用复制构造函数生成s1,s1为str的复制品
cout<<s1<<endl;
string s2(str,6); //将str内,开始于位置6的部分当作s2的初值
cout<<s2<<endl;
string s3(str,6,3); //将str内,开始于6且长度顶多为3的部分作为s3的初值
cout<<s3<<endl;
string s4(cstr); //将C字符串作为s4的初值
cout<<s4<<endl;
string s5(cstr,3); //将C字符串前3个字符作为字符串s5的初值。
cout<<s5<<endl;
string s6(5,'A'); //生成一个字符串,包含5个'A'字符
cout<<s6<<endl;
string s7(str.begin(),str.begin()+5); //区间str.begin()和str.begin()+5内的字符作为初值
cout<<s7<<endl;
return 0;
}

2.string的比较等操作
你可以用 ==、>、<、>=、<=、和!=比较字符串,可以用+或者+=操作符连接两个字符串,并且可以用[]获取特定的字符。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
cout << "Please input your name:"<<endl;
cin >> str;
if( str == "Li" ) // 字符串相等比较
cout << "you are Li!"<<endl;
else if( str != "Wang" ) // 字符串不等比较
cout << "you are not Wang!"<<endl;
else if( str < "Li") // 字符串小于比较,>、>=、<=类似
cout << "your name should be ahead of Li"<<endl;
else
cout << "your name should be after of Li"<<endl;
str += ", Welcome!"; // 字符串+=
cout << str<<endl;
for(int i = 0 ; i < str.size(); i ++)
cout<<str[i]; // 类似数组,通过[]获取特定的字符
return 0;
}

3.string特性描述
可用下列函数来获得string的一些特性:
- int capacity()const; //返回当前容量(即string中不必增加内存即可存放的元素个数)
- int max_size()const; //返回string对象中可存放的最大字符串的长度
- int size()const; //返回当前字符串的大小
- int length()const; //返回当前字符串的长度
- bool empty()const; //当前字符串是否为空
- void resize(int len,char c); //把字符串当前大小置为len,多去少补,多出的字符c填充不足的部分
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
if (str.empty())
cout<<"str is NULL."<<endl;
else
cout<<"str is not NULL."<<endl;
str = str + "abcdefg";
cout<<"str is "<<str<<endl;
cout<<"str's size is "<<str.size()<<endl;
cout<<"str's capacity is "<<str.capacity()<<endl;
cout<<"str's max size is "<<str.max_size()<<endl;
cout<<"str's length is "<<str.length()<<endl;
str.resize(20,'c');
cout<<"str is "<<str<<endl;
str.resize(5);
cout<<"str is "<<str<<endl;
return 0;
}

其他函数:
- string &insert(int p,const string &s); //在p位置插入字符串s
- string &replace(int p, int n,const char *s); //删除从p开始的n个字符,然后在p处插入串s
- string &erase(int p, int n); //删除p开始的n个字符,返回修改后的字符串
- string substr(int pos = 0,int n = npos) const; //返回pos开始的n个字符组成的字符串
- void swap(string &s2); //交换当前字符串与s2的值
- string &append(const char *s); //把字符串s连接到当前字符串结尾
- void push_back(char c) //当前字符串尾部加一个字符c
- const char data()const; //返回一个非null终止的c字符数组,data():与c_str()类似,用于string转const char其中它返回的数组是不以空字符终止,
- const char *c_str()const; //返回一个以null终止的c字符串,即c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同,用于string转cons
本文介绍了C++中的引用概念,包括引用的本质、使用规则及在函数参数和返回值中的应用。接着讨论了内联函数的优势、缺点以及何时使用,解释了内联函数的工作原理。最后,概述了string类的关键特性,如比较、连接和修改字符串的方法。
1042

被折叠的 条评论
为什么被折叠?



