一些C++语法很难懂,比如左值、右值和std::move的关系,这时候如果有示例的话就好了。

一、原理篇

一、编译

  • 变量和指针等的地址是在编译期确定的,这一地址可以认为是局部地址或虚拟地址,仅在该程序内有效。在运行时,由操作系统完成从该虚拟地址和物理地址之间的映射关系。
  • 变量在编译后,保存的是地址。当执行一个加法a+b的时候,直接到两个变量对应的地址中取值。
  • 新建一个对象时,类的成员变量才会占用内存空间,成员函数不会额外空间。
  • publicprotectedprivate这些类的访问限制是在编译期中使用的,编译得到的二进制的可执行程序中,没有访问限制这种东西。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循环一样,在遍历的过程中如果修改容器,会造成迭代器失效。因此,上述代码在运行时会崩溃。

#####