c++基础知识入门,c++基础知识面试题

  c++基础知识入门,c++基础知识面试题

  带有static关键字的全局变量只能在本文档中使用。

  Static定义的静态局部变量分配在数据段上,普通局部变量分配在堆栈上,会因为函数堆栈框架的释放而被释放。

  1.1全局静态变量

  在全局变量前加关键字static,全局变量定义为全局静态变量。

  内存中的位置:静态存储区域,在程序运行过程中一直存在。

  初始化:未初始化的全局静态变量会自动初始化为0(自动对象的值是任意的,除非显式初始化);

  作用域:全局静态变量只有在声明时才在这个文件中可见,而在其文件外不可见。准确地说,它从定义开始,到文件结尾结束。

  1.2局部静态变量

  在局部变量前加上关键字static,局部变量就成了局部静态变量。

  内存中的位置:静态存储区域,在程序运行过程中一直存在。

  初始化:未初始化的全局静态变量会自动初始化为0(自动对象的值是任意的,除非显式初始化);

  作用域:作用域仍然是局部作用域,当定义它的函数或语句块结束时,作用域也就结束了。但是,当局部静态变量离开作用域时,它并没有被销毁,而是仍然驻留在内存中,只是我们不能再次访问它,直到函数被再次调用,其值保持不变。

  1.3静态功能

  在函数返回类型前添加static,函数被定义为静态函数。默认情况下,函数的定义和声明都是extern的,但是静态函数只在这个文件中可见,不能被其他文件使用。

  函数的实现是用static修饰的,所以这个函数只能在这个cpp中使用,不会和cpp中其他同名函数造成冲突;

  警告:在头文件中声明非静态全局函数,在cpp中声明静态全局函数。如果要在多个CPP中重用这个函数,在头文件中提及它的声明,否则CPP内部声明需要用static修饰;

  1.4类的静态成员

  对于类中的成员变量和成员函数,如果添加了static关键字,这个变量/函数将没有this指针,必须通过类名访问。

  在类中,静态成员可以实现多个对象之间的数据共享,使用静态数据成员不会打破隐藏的原则,即保证安全性。因此,静态成员是一个类的所有对象共享的成员,而不是一个对象的成员。对于多个对象,静态数据成员只存储在一个地方,由所有对象共享。

  1.5类静态函数

  像静态数据成员一样,静态成员函数属于类的静态成员,它们不是对象成员。因此,对静态成员的引用不需要使用对象名。在静态成员函数的实现中,不能直接引用类中描述的非静态成员,但是可以引用类中描述的静态成员(这一点很重要)。如果要引用静态成员函数中的非静态成员,可以通过对象来引用。可以看出,静态成员函数的调用格式如下:类名:静态成员函数名(参数表

  C和C的区别

  2.1设计思路

  C是面向对象的语言,而C是面向过程的结构化编程语言。

  2.2语法上

  c有三个特点:重载、继承、多态;

  与C相比,C有更多类型的安全函数,如强制类型转换;

  c支持范式编程,比如模板类和函数模板。

  c #中的四次强制转换

  C中的四种转换类型是:static _ cast、dynamic _ cast、const _ cast和reinterpret _ cast。

  3.1常数_转换

  用于将常量变量转换为非常量变量。它也是四个cast运算符中唯一可以移除const属性的运算符。对于未定义const版本的成员函数,我们通常需要使用const_cast来移除const引用对象的const,完成函数调用。另一种使用方法,结合static_cast,就是在非const版本的成员函数中加入const,调用const版本的成员函数后,再用const_cast去掉const限定。

  3.2静态_转换

  ` ` c

  static_cast new_type(表达式)

  //new_type是目标数据类型,expression是原始数据类型变量或表达式。

  基本数据类型之间的转换,比如int、float、char用于各种* *隐式转换* *,比如非const到const,void*到指针等。但是* *没有运行时类型检查来确保转换* *的安全性。

  * *隐式类型转换* *:首先,对于内置类型,隐式类型转换发生在低精度变量给高精度变量赋值的时候。其次,对于构造函数只有一个参数的对象构造,可以使用这个参数直接传入函数调用,编译器会自动调用其构造函数生成* *临时对象* *。

  Static_cast主要用于以下几个方面:

  1.用于类层次结构中* *基类* *和* *派生类* *之间的指针或引用的转换。

  是* *安全* *让* *向上* *转化;

  当执行* * down * *转换时,它是* *不安全的* *,因为没有动态类型检查。因为基类不包含派生类的成员变量,所以派生类的成员变量不能赋值。

  2.它用于基本数据类型之间的转换,如int、float和char。

  3.将空指针转换为* *目标类型* *的空指针。

  4.将任何类型的表达式更改为* *并替换为void类型* *。

  注意:static_cast无法* *移除* *表达式的const、volatile或__unaligned属性。

  ` ` c

  char a= aInt=static _ cast char//将char数据转换为int数据

  const int g=20

  Int *h=static_cast int* (//编译错误,static_cast无法移除g的const属性。

  ` ` c

  类别基础

  {};

  类别衍生:公用基底

  {}

  Base pB=new Base();

  if(Derived pD=static _ cast Derived *(pB))

  { }//下行转换不安全(坚决抵制这种方法)

  Derived pD=new Derived();

  if(Base pB=static_cast Base* (pD))

  { }//上行转换安全。

  ## 3.3动态_转换

  ` ` c

  动态转换新类型(表达式)

  //new_type是目标数据类型,expression是原始数据类型变量或表达式。

  Dynamic_cast type* (e) //type必须是类类型和有效指针。

  Dynamic_cast type (e) //type必须是类类型和左值。

  Dynamic_cast type (e) //type必须是类类型和右值。

  用于动态类型转换。它只能用于包含虚函数的类,可以用于类级别之间的上下转换和类之间的交叉强制转换。只能旋转指针或引用。

  在类之间向上转换时,dynamic_cast和static_cast的效果是相同的。在向下转换期间,dynamic_cast具有类型检查功能。它通过判断变量类型是否与语句执行时要转换的类型相同来判断是否可以进行下转换。如果不合法,则返回NULL,转换目标为指针类型,抛出std:bad_cast异常进行引用比static_cast更安全。

  3.4重新解释_演员表

  几乎什么都可以转,比如把int转指针,这就是逐位复制的操作。容易出错,尽量少用。

  3.5为什么不用C的强制转换?

  C的强制转换表面上看起来很强大,可以转换任何东西,但是转换不够清晰,无法检查错误,容易出错。

  C/C中指针和引用的区别

  4.1指针

  指针使用地址,它的值直接指向存储在计算机内存中另一个地方的值。因为通过地址可以找到所需的变量单元,所以可以说地址指向了变量单元。因此,可视化的地址被称为“指针”。这意味着可以找到它所寻址的存储单元。

  4.2引用

  引用是变量的别名,引用的操作和变量的直接操作完全一样。引用的声明方法:类型标识符引用名=目标变量名;引入了对象的同义词。引用的表达方式与定义指针相同,只是*被替换为。

  4.3差异

  指针有自己的空格,引用只是别名;

  用sizeof看到指针的大小是4,而引用是被引用对象的大小;

  指针可以初始化为NULL,而引用必须初始化,并且必须是对已有对象的引用;

  当作为参数传递时,指针需要解引用才能对对象进行操作,引用的修改会改变引用所指向的对象;

  可以有常量指针,但是没有常量引用;

  指针可以指向其他正在使用的对象,但引用只能是一个对象的引用,不能更改;

  指针可以有多级指针(**p),引用到第一级;

  指针和引用使用含义不同的运算符;

  如果返回动态分配的对象或内存,则必须使用指针,这可能会导致内存泄漏。

  c智能指针

  C中有四个智能指针:auto _ ptr、shared _ ptr、weak _ ptr、unique _ ptr。后三个是c 11支持的,第一个已经被11抛弃了。

  为什么使用智能指针:

  智能指针的作用是管理一个指针,因为有一种情况是在函数结束时忘记释放被请求的空间,导致内存泄漏。智能指针可以在很大程度上避免这个问题,因为智能指针是一个类。当超出类的范围时,类会自动调用析构函数,析构函数会自动释放资源。所以智能指针的原理是在函数结束时自动释放内存空间,不需要手动释放内存空间。

  在初始化shared_ptr时,不能直接给智能指针赋一个公共指针,因为一个是指针,一个是类。可以通过make_shared函数或构造函数传入一个公共指针。并且可以通过get函数得到一个公共指针。

  5.1自动_ptr

  C 98方案,cpp11已经废弃。

  ` ` c

  auto_ptr string p1(新字符串(我独霸寂寞如云。"));

  auto_ptr字符串

  p2=p1//auto_ptr不会报错。

  此时不会报告错误,**p2剥夺了p1的所有权* *,但是在程序运行时访问p1会报告错误。因此,auto_ptr存在潜在的内存崩溃问题。

  ## 5.2唯一_ptr

  替换auto_ptr。Unique_ptr实现了* *独占所有权* *或者严格所有权的概念,保证同一时间只有一个智能指针可以指向对象。这对于避免资源泄漏特别有用(例如,在用new创建一个对象后,由于一个异常而忘记调用delete)。还是上面的例子:

  ` ` c

  unique_ptr字符串p3(新字符串( auto ));//#4

  unique_ptr字符串P4;//#5

  p4=p3//此时会报错!

  编译器认为p4=p3是非法的,从而避免了p3不再指向有效数据的问题。所以unique_ptr比auto_ptr更安全。此外,unique_ptr更聪明:当一个程序试图将一个unique_ptr赋给另一个时,如果源unique_ptr是临时右值,编译器允许;如果源unique_ptr会存在一段时间,编译器会禁止这样做,比如:

  ` ` c

  unique_ptr string pu1(新字符串(hello world));

  unique_ptr字符串pu2

  pu2=pu1//#1不允许

  unique_ptr字符串pu3

  pu3=unique_ptr string(新字符串(你));//#2允许

  其中#1留下悬挂unique_ptr(pu1),可能造成伤害。而#2不会离开悬挂的unique_ptr,因为它调用的是unique_ptr的构造函数,这个构造函数创建的临时对象在所有权给了pu3之后就会被销毁。这种依赖于情况的行为表明unique_ptr优于auto_ptr,后者允许两次赋值。

  注意:如果你真的想做类似于#1的事情,你可以通过赋予它一个新的值来安全地重用这个指针。c有一个标准的库函数**std:move()**,它使您能够将一个unique_ptr赋给另一个。例如:

  ` ` c

  unique_ptr字符串ps1,ps2

  PS1=demo( hello );

  PS2=move(PS1);

  ps1=demo(失读症);

  cout * ps2 * ps1 endl

  5.3共享_ptr

  Shared_ptr实现了共享所有权的概念。多个智能指针可以指向同一个对象,当最后一个引用被销毁时,该对象及其相关资源将被释放。从名称share可以看出,资源可以被多个指针共享。它使用计数机制来指示资源由几个指针共享。您可以通过成员函数use_count()检查资源所有者的数量。除了new,还可以通过传入auto _ ptr、unique _ ptr、weak _ ptr来构造。当我们调用release()时,当前指针将释放资源所有权,计数将减一。当计数等于0时,资源将被释放。

  Shared_ptr是为了解决auto_ptr在对象所有权上的限制(auto_ptr是独占的),在使用引用计数的机制上提供了一个可以共享所有权的智能指针。

  成员函数:

  Get返回内部对象(指针)。因为()方法已经被重载,所以它与直接使用对象是一样的。比如:

  ` ` c

  shared _ ptr int sp(new int(1));//sp相当于sp.get()

  5.4弱_ptr

  Weak_ptr是一个不控制对象生命周期的智能指针。它指向由shared_ptr管理的对象。weak_ptr设计的目的是引入智能指针辅助shared_ptr。它只能由一个shared_ptr或另一个weak_ptr对象构造,它的构造和销毁不会引起引用计数的增减。

  Weak_ptr用于解决shared _ ptrs相互引用时的死锁问题。如果两个shared _ ptrs相互引用,这两个指针的引用计数永远不会降到0,资源永远不会被释放。它是对对象的弱引用,不会增加对象的引用计数。可以转换成shared_ptr,可以直接赋值给它。它可以通过调用lock函数获得shared_ptr。

  ` ` c

  B类;

  A级

  {

  公共:

  sharedptr B pb

  ~A()

  {

  cout A删除\n

  }

  };

  B类

  {

  公共:

  sharedptr A pa

  ~B()

  {

  cout B删除\n

  }

  };

  虚空乐趣()

  {

  shared _ ptr B Pb(new B());

  shared ptr A pa(new A());

  p B- pa=pa;

  pa-Pb _=Pb;

  cout Pb . use _ count()endl;

  cout pa . use _ count()endl;

  }

  int main()

  {

  fun();

  返回0;

  }

  可以看到在fun函数中pa和pb相互引用,两个资源的引用计数都是2。当你想跳出函数的时候,智能指针pa和pb析构的时候两个资源的引用计数都会减一,但是两个资源的引用计数仍然是1,导致你跳出函数的时候资源没有被释放(A B的析构函数没有被调用)。如果你把其中一个改成weak_ptr,那么把我们A类中的‘shared _ ptr Pb’改成‘weak _ ptr Pb’的运行结果如下。这样,资源B的引用一开始只有1。当pb被析构时,B的计数变为0,B被释放。当B被释放时,它也会将A的计数减一,当pa被析构时,它会将A的计数减一,这样A的计数为0,A被释放。

  注意,我们不能通过weak_ptr直接访问对象的方法。比如对象B中有一个方法print(),我们不能这样访问它,` pa-p B-print();`英文pb_是一个weak_ptr,要先转换成shared_ptr,比如:

  ` ` c

  shared_ptr p=pa- pb_。lock();

  p打印();

  5.5内存泄漏

  当两个对象使用一个shared_ptr成员变量指向对方时,会造成循环引用,使引用计数无效,导致内存泄漏。

  #包括iostream

  #包括内存

  使用命名空间std

  B类;

  A级

  Public: //为了节省一些步骤,数据成员在这里也被声明为Public。

  共享_ptr B

  ~A()

  cout kill A \ n

  B类

  公共:

  shared_ptr A

  ~B()

  cout kill B \ n

  int main(int argc,char** argv)

  shared _ ptr A sa(new A());

  shared _ ptr B sb(new B());

  如果(sa sb)

  sa-Pb=sb;

  s b-pa=sa;

  cout sa use count: sa . use _ count()endl;

  返回0;

  }

  注意此时SA和SB没有释放,导致内存泄漏。即A指向B and B指向A,这样对于A,B必须在A析构后析构,对于B,A必须在B析构后析构A。这就是循环引用问题,违反了约定,导致内存泄漏。

  使用弱引用智能指针weak_ptr来打破这种循环引用。为了解决循环引用造成的内存泄漏,引入了弱指针weak_ptr。weak_ptr的构造函数不会修改引用计数的值,所以不会管理对象的内存。它类似于一个普通的指针,只是不指向引用计数的共享内存,但是可以检测被管理对象是否已经被释放,从而避免非法访问。

  5.6 shared _ ptr的实现

  ` ` c

  模板类型名T

  类别SmartPtr

  {

  私人:

  T ptr//底层实指针

  int use _ count//保存有多少指针指向当前对象的计数。

  公共:

  smart ptr(T p);//smart ptr int p(new int(2));

  smart ptr(const smart ptr T orig);//smart ptr int q(p);

  smart ptr T operator=(const smart ptr T RHS);//q=p

  ~ smart ptr();

  t运算符();//定义取消引用操作,以便将智能指针视为普通指针操作。

  to operator-//定义成员提取操作

  t运算符(int I);//定义指针加一个常数

  int运算符-(SmartPtr T t1,smart ptr T T2);//定义两个指针的减法

  void getcount()

  {

  return *使用次数

  }

  };

  模板类型名T

  int smart ptr T:operator-(smart ptr T t1,SmartPtr T t2)

  {

  返回t1 . ptr-T2 . ptr;

  }

  模板类型名T

  SmartPtr T :SmartPtr(T p)

  {

  ptr=p;

  尝试

  {

  use _ count=new int(1);

  }

  接住(.)

  {

  删除ptr//应用程序无法释放实际指针和引用计数的内存。

  ptr=nullptr

  删除use _ count

  use _ count=nullptr

  }

  }

  模板类型名T

  smart ptr t:smart ptr(const smart ptr t orig)//复制构造函数

  {

  use _ count=orig.use _ count//引用计数保存在内存块中,所有SmarPtr对象的引用计数。

  所有观点都在这里。

  this-ptr=orig . ptr;

  (use _ count);//当前对象的引用计数增加1

  }

  模板类型名T

  SmartPtr T SmartPtr T:operator=(const SmartPtr T RHS)

  {

  //Overload=operator,如smart ptr int p=q;在这个语句中,首先在Q指向的对象的引用计数上加1,因为P再次指向Q指向的对象,所以P需要先在原对象的引用计数上减1。如果减法后是0,先释放P原来指向的内存,然后将Q指向的对象的引用计数加1,赋给P。

  (RHS . use _ count);

  if (( - (use_count))==0)

  {

  删除ptr

  ptr=nullptr

  删除use _ count

  use _ count=nullptr

  }

  ptr=rhs.ptr

  use _ count=(RHS . use _ count);

  还这个;

  }

  模板类型名T

  SmartPtr T :~SmartPtr()

  {

  getcount();

  if(-(use _ count)==0)//smart ptr的对象将在生命周期结束时调用其析构函数。在析构函数中,检查当前对象的引用计数是否只是结束其生命周期的那个。如果有,就放生吧。如果没有,则有其他SmartPtrs引用当前对象。只需等待其他smartptr对象在生命周期结束时调用析构函数来释放它。

  {

  getcount();

  删除ptr

  ptr=nullptr

  删除use _ count

  use _ count=nullptr

  }

  }

  模板类型名T

  T SmartPtr T:运算符()

  {

  返回ptr

  }

  模板类型名T

  T SmartPtr T :operator-()

  {

  返回ptr

  }

  模板类型名T

  T SmartPtr T:运算符(int i)

  {

  t * temp=ptr I;

  返回温度;

  }

  # 6数组和指针

  指针数组

   - -

  保存数据的地址保存数据

  指针的内容是访问数据的地址对数据的直接访问

  通常用于动态数据结构通常用于相同数据类型的固定数量的元素

  通过Malloc分配内存,释放内存隐式分配和删除

  通常指匿名数据,匿名函数本身就是数据名

  # 7野生指针

  通配符指针是指向* *已删除对象* *或* *未申请访问* *的* *受限内存区域的指针。

  # 8函数指针

  ## 8.1定义

  函数指针是指向函数变量的指针。

  函数指针本身首先是一个指针变量,指向一个特定的函数。正如指针变量可以指向整数变量、字符类型和数组一样,这里也有指向函数。

  编译C时,每个函数都有一个入口地址,就是函数指针指向的地址。当你有一个指向函数的指针变量时,你可以用指针变量调用函数,就像你可以用指针变量引用其他类型的变量一样。这些概念大体上是一致的。

  ## 8.2用途:

  调用函数和函数的参数,比如回调函数。

  ## 8.3示例:

  ` ` c

  Char * fun(char * p) {…} //函数fun

  char *(* pf)(char * p);//函数指针pf

  pf=好玩;//函数指针pf指向函数fun

  pf(p);//通过函数指针pf调用函数fun

  9叉功能

  Fork:创建一个像当前流程映像一样的流程可以被fork()系统调用:

  ` ` c

  #包含sys/types.h

  #包括unistd.h

  PID _ t fork(void);

  成功调用fork()将* *创建一个新的进程* *,它与调用fork()的进程几乎相同,两个进程都将继续运行。在子流程中,成功的fork()调用将返回0。父进程中的Fork()返回子进程的pid。如果出现错误,fork()将返回负值。

  fork()最常见的用法是创建一个新进程,然后使用**exec( )**加载二进制映像,替换当前进程的映像。在这种情况下,一个新的进程被fork,这个子进程将执行一个新的二进制可执行映像。这种“推导加执行”的方式很常见。

  在早期的Unix系统中,创建过程相对原始。当fork被调用时,内核会对所有内部数据结构进行复制,复制进程的页表项,然后将父进程地址空间中的内容逐页复制到子进程的地址空间中。但是从内核的角度来说,逐页复制是非常耗时的。现代Unix系统采用了更多的优化,比如Linux,采用了* *写时拷贝* *的方法,而不是整体拷贝父进程空间进程。

  # 10析构函数

  析构函数对应于构造函数。当一个对象结束生命周期时,比如对象所在的函数已经被调用,系统会自动执行析构函数。

  构造函数名也应该和类名一样,只是通过加一个位反转~来和构造函数区分,比如` ~stud()`。它* *不能带任何参数,也没有返回值* *(包括void类型)。只能有一个析构函数,* *不能重载* *。

  如果用户没有写析构函数,编译系统会自动生成一个默认的析构函数(即使自定义了析构函数,编译器也会一直为我们合成一个析构函数,如果自定义了析构函数,编译器在执行时会先调用自定义的析构函数,再调用合成的析构函数),什么也不做。所以很多简单的类不使用显式析构函数。

  如果一个类中有一个指针,并且在使用过程中动态请求内存,那么最好在销毁该类之前表明构造函数释放了所请求的内存空间,以避免内存泄漏。

  ## 10.1类破坏顺序

  1.派生类本身的析构函数

  2.对象成员析构函数

  3.基类的析构函数

  因为析构函数没有参数,所以包含成员对象的类的析构函数没有什么特别的。但是撤销类对象时,会先调用自己的析构函数,然后调用成员对象的析构函数。调用顺序与初始化顺序相反。

  # 11虚函数和多态性

  多态性的实现主要分为* *静态多态性* *和* *动态多态性* *。静态多态主要是重载* *,是* *编译* *的时候确定的;* *动态多态通过虚函数* *机制实现,在* *运行时* *动态绑定。比如当一个父类的指针指向一个子类对象时,当父类的指针用来调用父类中已经* *重写* *在子类中的虚函数时,就会调用子类重写的函数,在父类中声明为带有virtual关键字的函数。在子类中重写时,也是虚函数,不加虚。

  虚函数的实现:在有虚函数的类中,类的初始部分是一个虚函数表的* *指针* *。这个指针指向一个* *虚函数表* *其中放置了虚函数的地址。实际的虚函数在代码段(。正文)。当子类继承其父类时,它也将继承其虚函数表。子类重写父类中的虚函数时,会用重写后的函数地址* *替换其继承的* *虚函数表地址。使用虚函数会增加内存访问开销,降低效率。

  # 12析构函数和虚函数

  析构函数必须是虚函数,因为将可能被继承的父类的析构函数设置为虚函数,可以保证当我们创建一个子类,然后用基类指针指向子类对象,* *基类指针释放* *,就可以释放子类的空间,从而防止内存泄漏。

  c的默认析构函数不是虚函数,因为虚函数需要额外的虚函数表和虚表指针,占用了额外的内存。对于不会被继承的类,如果它的析构函数是虚函数,就会浪费内存。所以C的默认析构函数不是虚函数,只是在需要作为* * * *的父类时,* *才设置虚函数* *。

  # 13静态函数和虚拟函数

  静态函数在编译时就已经确定了运行时间,虚函数在运行时是动态绑定的。因为虚函数使用虚函数表机制,所以调用一次就会增加内存开销。

  ## 13.1静态功能

  用static修饰的函数仅限于在该源文件中使用,不能被该源文件以外的代码文件调用。普通函数,默认是extern,也就是说可以被其他代码文件调用。

  ## 13.2虚函数表

  当一个类包含由虚拟关键字修饰的成员函数时,该成员函数就变成了* *虚函数* *。第一个包含虚函数的类实例化的所有对象都有相同的* *虚函数表* *,对象包含一个* *虚函数指针*_vptr**,指向该类的虚函数表。虚函数表存储了类中虚函数的地址(一个类可以有多个虚函数)。

  ## 13.3虚函数功能

  当一个子类继承了一个具有虚函数的基类,并在基类中重写了一个虚函数时,我们说这两个类构成了多态性。当子类继承基类时,基类的虚函数表也被子类继承。不同的是子类* *重写的虚函数会替换原虚函数表中对应基类虚函数的地址* *。这样,当一个基类和一个子类调用一个同名的虚函数时,就不是同一个函数了,这就体现了多态和虚函数表的作用。

  ## 13.4静态功能和虚拟功能的区别

  我们知道我们类的静态函数没有这个指针。调用时,我们不需要创建对象,直接以:类名:函数名(参数)的形式调用。静态函数只有一个* *唯一的* *副本,所以它的* *地址是固定的* *。所以在编译的时候,无论什么时候调用静态函数,你都知道调用的是哪个函数。所以说* *静态函数的运行时间在编译的时候就已经确定了。* *虚函数不是。请看下面的代码:

  ` ` c

  A级

  公共:

  虚拟虚空乐趣()

  cout 我是一个endl

  B类:公共A

  公共:

  虚拟虚空乐趣()

  cout 我是B endl

  int main()

  A a

  B b

  A* pb=

  p B- fun();

  返回0;

  }

  a类和b类是多态的,创建a类指针pb指向b类对象。程序编译的时候只检查语法,这个语句没有错。但是编译器无法确定此时调用的是哪个fun()函数,因为a类和b类都包含fun函数,所以只能在程序运行时通过pb指针查看对象的虚函数表(访问虚函数表称为访问内存)来确定这个函数的地址。这就解释了所谓的“运行时动态绑定虚函数”。因为虚函数使用虚函数表机制,所以调用一次就会增加内存开销。"

  14重载和覆盖

  14.1超载

  钍

  子类继承父类,父类中的函数是虚函数。这个虚函数是在子类中重新定义的,是一种同名的覆盖。

  在主函数之前运行的15个函数

  1.test0: _ _ attribute ((constructor))是gcc的扩展,表示这个函数应该在main函数之前执行。还有_ _属性((destroyer)),标记函数要在程序结束之前(main结束之后或者exit调用之后)执行。

  2.test1:全局静态变量的初始化在程序的初始阶段,在主函数执行之前。

  ` ` c

  #包括iostream

  使用命名空间std

  _ _属性((构造函数))void test0()

  {

  printf(在main 0之前\n

  }

  int test1()

  {

  main 1 endl之前的cout

  返回54;

  }

  static int I=test1();

  int main(int argc,char** argv)

  {

  cout主函数。endl

  返回0;

  }

  在leetcode中经常看到Static,以及通过在main之前关闭cin和stdin的同步来“提速”的黑科技。

  ` ` c

  静态int _=[]{

  CIN . sync _ with _ stdio(false);

  返回0;

  }();

  16内存管理

  在C中,虚拟内存分为六个部分:代码段、数据段、BSS段、堆区、文件映射区和堆栈区。

  1.堆栈:程序自动分配,堆栈空间用于存储函数的返回地址、参数、局部变量和返回值。

  2.堆:

  Heap:调用malloc在堆区动态分配内存,调用free手动释放。堆是由操作系统维护的特殊内存,提供动态分配的功能。

  自由存储区:new分配的内存用于delete手动释放。类似于heap,new申请的内存区域可以称为空闲内存区域。

  3.静态/全局区:在c中bss和数据没有区别。

  Segment bss:存储未初始化的全局变量和静态变量(局部全局变量),并将所有初始化的全局变量和静态变量置为0,以符号开始的块。

  段:存储程序中初始化的全局变量数据静态变量。

  4.代码区(代码段或文本段):

  代码:存储函数体、文本段的二进制代码。

  常量区:只读数据,如字符串常量,在程序结束时由系统释放。Rodata段,只读。

  段初始化:程序初始化入口代码,在main()之前运行。

  17常量const

  常量是一个固定值,在程序执行过程中不会改变。常量可以是任何基本数据类型,可以分为int、float、char、string和bool。常量定义必须初始化。

  17.1储存区域

  局部常数,存储在堆栈区;

  静态/全局常数,存储在静态/全局存储区;

  字面常量,其值一看就知道,存储在常量区。

  17.2常量修改成员函数

  Const修饰的成员函数指示函数调用不会对对象进行任何更改。实际上,如果确认对象不会被改变,那么函数就应该用const限定,这样const对象和普通对象都可以调用函数。

  如果同时定义了两个函数,一个有const,另一个没有const,这就相当于重载了函数。

  18代码分析

  18.1 strcpy和strlen

  Strcpy是一个字符串复制函数,原型:

  ` ` c

  char strcpy(char dest,const char * src);

  将* *从src **逐字节复制到dest,直到遇到 \0 的结尾。因为没有指定长度,所以复制可能会越界,从而导致缓冲区溢出漏洞。安全版本是strncpy函数。

  strlen函数是一个计算字符串长度并返回从开始到 \0 的字符数的函数。

  ## 18.2我和我

  一.实施:

  ` ` c

  int int:operator()

  * this=1;

  返回* this

  }

  一.实施:

  ` ` c

  const int int:operator(int)

  {

  int oldValue=this

  (这个);

  返回旧值;

  }

  ## 18.3代码差异

  (1)字符串123被存储在* *恒定区域* *中。const本来是用来修改arr指向的值的,但是字符串“123”在常量区,所以不能修改,所以有没有const效果都一样:

  ` ` c

  const char * arr= 123

  (2)字符串123被存储在恒定区域中。这与arr指针的位置相同,并且值123不能被brr修改:

  ` ` c

  char * brr=123

  (3)这里123 本来是在栈上的,但是编译器可能会做某些优化,将其放到常量区:

  ` ` c

  const char crr[]= 123 ;

  (4)字符串123 保存在栈区,可以通过背根反射去修改:

  ` ` c

  char drr[]=123

  # 19 编程题

  ## 19.1 点是在三角形内

  给定三角形字母表和一点P(x,y,z),判断点P是否在字母表内。

  根据面积法,如果P在三角形字母表内,那么三角形雄激素结合蛋白的面积三角形业务连续性计划的面积三角形酰基-载体蛋白质(酰基载体蛋白)的面积应该等于三角形字母表的面积。

  s=(x _ 1y _ 2 x _ 2y _ 3 x _ 3y _ 1-x _ 1y _ 3-x _ 2y _ 1-x _ 3y _ 2)/2

  代码如下:

  ` ` c

  #包括输入输出流

  #包含数学。h

  使用命名空间标准

  #define ABS_FLOAT_0 0.0001

  结构点_浮点

  浮动x;

  浮动y;

  浮点GetTriangleSquar(定点_浮点pt0,定点_浮点pt1,定点_浮点pt2) //计算三角形面积

  point_float AB,BC;

  ab。x=pt1。x-pt0。x;

  ab。y=pt1。y-pt0。y;

  公元前。x=pt2。x-pt1。x;

  公元前。y=pt2。y-pt1。y;

  返回法布斯((ab。公元前x年。y-ab。公元前y年。x))/2.0f;

  布尔是三角形(常量点_浮点一,常量点_浮点b,常量点_浮点c,常量点_浮点D) //判断给定一点是否在三角形内或边上

  浮动南非银行、SADB、SBDC、南部非洲发展共同体;

  SABC=GetTriangleSquar(A,B,C);

  SADB=GetTriangleSquar(A,D,B);

  SBDC=GetTriangleSquar(B,D,C);

  SADC=GetTriangleSquar(A,D,C);

  SADBSBDC南部非洲发展共同体;

  if((-ABS _ FLOAT _ 0(SABC-SumSuqar))((SABC-SumSuqar)ABS _ FLOAT _ 0))

  返回真实的

  其他

  返回错误的

  }

  19.2 判断一个数是二的倍数

  判断一个数是不是二的倍数,即判断该数二进制末位是不是0:

  ` ` c

  a % 2==0

  a0x0001==0 //两种办法都可

  ## 19.3 一个数中有几个一

  可以直接逐位除十取余判断:

  int fun(long x)

  {

  int _ count=0;

  while(x)

  {

  if(x % 10==1)

  _计数

  x/=10;

  }

  返回_计数;

  }

  int main()

  {

  cout fun(123321)endl;

  返回0;

  }

  不间断空格

  不间断空格

  **学习更多编程知识,请关注我的公众号:**

  [代码的路](https://MP。微信。QQ。com/s/t 0t 89 dfgj 1 tezi 4 ui 5 gihg)

  ![](https://s 2.51 CTO。com/images/blog/202208/08103042 _ 62f 07552 f 291194896。jpg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_30,g_se,x_10,y_10,shadow_20,type _ zm fuz 3 poz w5 nagvpdgk=/resize,m_fixed,w_750)

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: