一些C++语法很难懂,比如左值、右值和std::move
的关系,这时候如果有示例的话就好了。
一、原理篇
一、编译
- 变量和指针等的地址是在编译期确定的,这一地址可以认为是局部地址或虚拟地址,仅在该程序内有效。在运行时,由操作系统完成从该虚拟地址和物理地址之间的映射关系。
- 变量在编译后,保存的是地址。当执行一个加法
a+b
的时候,直接到两个变量对应的地址中取值。 - 新建一个对象时,类的成员变量才会占用内存空间,成员函数不会额外空间。
public
protected
private
这些类的访问限制是在编译期中使用的,编译得到的二进制的可执行程序中,没有访问限制这种东西。const的修改限制也是如此。- const 变量的值可以在编译时或运行时确定,与 const 相比, constexpr 的限制更多,因为 constexpr 变量的值必须在编译时就能确定。
一、执行
- 如果实参是临时变量,形参不能是引用的形式。
- static变量的唯一性是动态库级别的,不同库包含同一截代码的话就会有多份static实例。
01 运用先初始化的成员的值来初始化其它成员
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
class Base
{
public:
int b;
Base(int in)
{
b=in;
}
};
class func
{
public:
~func(){};
func():a(1),b(func1())
{
}
int func1()
{
return a+1;
}
int a ;
Base b ;
};
int main(int argc,char** argv)
{
func f;
std::cout << f.b.b << std::endl;
return 0;
}
02 函数指针
/***** function and pointer *****/
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
std::ofstream os("123.txt");
class TS
{
public:
int fun8(int a, int b)
{
return a+b;
}
};
int fun(int a, int b)
{
int i = 0;
int* c = &i;
*c = a + b;
std::cout << "001: " << *c <<std::endl;
return *c;
}
int* fun3(int a, int b)
{
int i = 0;
int* c = &i;
*c = a + b;
std::cout << "002: " << *c <<std::endl;
return c;
}
int main()
{
int (*funcPtr)(int, int) = fun; // 创建一个返回值为 int 的函数指针
funcPtr(1,2);
std::cout << "003: " << &funcPtr << std::endl;
std::cout << *fun3(1,5) << std::endl; // 函数的返回值为一个指针
auto ff = &TS::fun8;
TS tt;
std::cout << "004: " << (tt.*ff)(3,2) << std::endl;
std::cout << "005: " <&ff << std::endl;
os << &ff ;
std::cout << std::endl;
const int x = 5, y = 6;
const int* p = &x;
y = x;
std::cout << "006: " << *p << std::endl;
return 0;
}
3
/***** right value and left value *****/
#####
-
编译时候类是知道自己有哪些no-virtual成员函数(编译器通过编码规则判断),并且下发所有被调用的成员函数首地址给了每一个对象,编译结束后,类不在关心自己有哪些成员函数,因为每一个对象都得到了分配,所以类中也就不用存贮函数的地址了.
-
在成员函数体内,成员变量的访问是通过在后台计算与this指针的偏移来进行。但不同的系统、编译器,使用的内存布局不一定相同,因此在编程过程中不能假设类的内存布局。
##### 由于引用不能为NULL,因此使用起来更安全。总体而言,请尽可能使用引用。但是,如果我们想编写同时使用C和C ++编译器进行编译的C代码,则必须限制使用指针。
#####
#include <iostream>
#include <vector>
using namespace std;
vector<int> vec = { 1, 2, 3, 4, 5, 6 };
int main()
{
for (auto n : vec)
{
cout << n << endl;
vec.push_back(7);
}
system("pause");
return 0;
}
在遍历容器的时候,在容器中插入一个元素导致迭代器失效了,因此,基于范围的for循环和普通的for循环一样,在遍历的过程中如果修改容器,会造成迭代器失效。因此,上述代码在运行时会崩溃。
#####