C++重要知识点拾忆

一:内联函数

函数调用也会带来降低效率的问题,因为调用函数实际上将程序执行顺序转移到函数所存放在内存中某个地址,将函数的程序内容执行完后,再返回到转去执行该函数前的地方。这种转移操作要求在转去前要保护现场并记忆执行的地址,转回后先要恢复现场,并按原来保存地址继续执行。
因此,函数调用要有一定的时间和空间方面的开销,于是将影响其效率。特别是对于一些函数体代码不是很大,但又频繁地被调用的函数来讲,解决其效率问题更为重要。引入内联函数实际上就是为了解决这一问题。
优点:可以加快代码的执行速度,当程序中调用内联函数时,该函数直接嵌入到每个调用语句处,每次函数调用时都用相对应的一段代码代替。可见它是以目标代码的增加为代价来换取时间的节省
主要解决功能相对简单、规模不大但使用相当频繁的程序运行效率问题。

使用内联函数时,遵守以下规则:

1. 内联函数体内不能包含任何静态变量,不能使用循环语句、switch;不能递归。

2.内联函数的定义必须出现在第一次被调用之前。

3.如果函数返回类型为void,则不能有return 语句。

二:指针

通过指针引用数组元素

int a[10];

int *p;

p++是合法的,而a++是错误的。a是数组名,它是数组的首地址,是常量;

指向函数的指针变量:存放函数入口地址,指向的是程序代码存储区。

1、函数调用可以通过函数名调用,也可以通过指向函数的指针变量调用。

2、(*p) ( )表示定义一个指向函数的指针变量,在程序中把哪个函数的地址赋给它,它就指向哪一个函数。

3、给函数指针变量赋值时,只需给出函数名而不必给出参数。 p = max

4、用函数指针变量调用函数时,只需将(*p)代替函数名,在(*p)之后的括弧中根据需要写实参。 c=(*p)(a,b)

5、对指向函数的指针变量不能运算

const pointer

一个指针涉及到两个变量,一个是指针本身,另一个是指向的变量

1.指向常量的指针
         const放在指针类型前,在程序中不能通过指针来间接修改指针所指向的内存空间的值,但可以改变指向的空间
    int a = 10;
    const int b = 20;
    const int* pa = &a;
    const int* pb = &b;
    a = 100;                    // ok
    b = 200;                   // error
   *pa = 100;               // error
   *pb = 200;              // error
    pb = &a;             // ok
    pa = &b;            // ok

2.指针常量
      const放在”*”和指针名之间,不能改地址能改所指向的值。
 int b =28;
int* const pb = &b;

*pb = 100;                   // ok
pb++;                       // error
在定义指针常量时,必须将其初始化。

3.指向常量的指针常量
     const在上述两个地方都加。既不允许修改指针值,也不允许修改指针变量所指向的值
const int a = 10;
const int * const pa = &a;

a = 100;    // error
*pa = 100;  // error
pa ++;  // error

三:引用

标题

引用与指针的区别
  引用是 C++ 语言引进的概念,在 C 语言中没有。

1)、指针是变量,引用是别名

引用是别名,引用本身没有地址。

2)、指针可作数组元素、引用不可

例: int *pa[5];//指针数组

int a[5];

int &rea[5]=a;//不可

3)、可以有空指针,不可有空引用

例: int *p=null;//合法

int &re=null;//无意义

四:类(class)

私有(private)的数据和函数,只允许本类的成员函数访问或调用;
保护(protected:)的数据和函数,允许本类和本类派生类的成员函数访问或调用;
公有(public:)的数据和函数,允许本类和其它类的函数访问或调用。

静态数据成员:

1.类的静态数据成员为该类的所有对象所共享。

2. 必须在类外文件作用域中的某个地方对静态数据成员赋初值(因为构造函数多次被调用,而静态数据成员只初始化1次):

<类型> <类名>::<静态数据成员> = <初值>

Const 成员函数中确保不会修改任何本类对象的数据成员。

class constfun
{
  private:
     int  a;
  public:
    void nonconstFunc( )
    {
       a=18;         //ok
    }
     void  Func( ) const
    {
      a=18         //error
    }
}
this指针:
    this指针是指向对象的指针,隐含在类的成员函数中,用来指向成员函数所属类的正在被操作对象。this指针可以看作是类自身的一个引用。

构造函数的调用顺序

对于构造函数,先执行基类的,再执行对象成员的,最后执行派生类的。

对于析构函数,先执行派生类的,再执行对象成员的,最后执行基类的。

导出类构造函数和析构函数的构建
基类的构造函数和析构函数不能被派生类继承。
如果基类没有定义构造函数,派生类也可以不定义构造函数,全都采用缺省的构造函数,此时,派生类新增成员的初始化工作可用其他公有函数来完成。
如果基类定义了带有形参表的构造函数,派生类就必须定义构造函数,提供一个将参数传递给基类构造函数的途径,以便保证在基类进行初始化时能获得必需的数据。
如果派生类的基类也是派生类,则每个派生类只需负责其直接基类的构造,不负责自己的间接基类的构造。
派生类是否要定义析构函数与所属的基类无关,如果派生类对象在撤销时需要做清理善后工作,就需要定义新的析构函数。

五:多重继承

解决二义性问题
解决方法一:用类名来限定(主要解决方法)   为避免二义性,可在调用时加上基类的名称,如 A::print() 或 B::print() 。
解决方法二:同名覆盖在C 中声明一个同名成员函数print(),f()再根据需要调用  A:: print()    或    B:: print()
解决方法三:使用虚函数

面向对象设计的三大机制: 数据封装、继承、多态。

  继承:研究的是类与类之间的层次关系。
  多态性:指不同的对象接收到相同的消息时产生不同的响应动作,即对相同的函数名,却执行不同的函数体。
  函数重载和运算符重载实现类的一种多态性。

静态联编和动态联编

联编(binding):是将函数调用与相应的函数体代码彼此关联的过程。

静态联编(static binding):如果联编过程在程序开始运行前的编译阶段完成。

例如:重载函数:

void fun(int a,int b)

void fun(float x,float y)

void fun(char c)

函数名字相同,但各自参数不同,编译器能根据函数参数的类型和个数自动选择相应的函数体编译。

动态联编(dynamic binding)

在程序运行时进行的联编方式。

例如:虚函数

C++中的虚函数,由于其函数名、返回值、函数参数完全相同,但函数体不同,因此编译阶段无法确定函数调用与哪个函数体关联,只能由系统在程序运行时确定。

六:虚函数

虚函数(virtual function)----运行时多态
  在定义某一基类(或其派生类)时,若将其中的某一函数成员的属性说明为virtual,则称该函数为虚函数。
       若基类中某函数被说明为虚函数,则意味着其派生类中也要用到与该函数同名、同参数表、同返回类型、但函数体不同。
     虚函数存在继承环境中。
虚函数成员的定义语法:
 virtual 函数类型 函数名(形参表)
   {
    函数体
    }
程序举例
class BaseClass
{
   public:
     virtual void show() {cout<<"Base class"<<endl;}
     //如果不加关键字virtual,运行的结果都是"Base class";
};
class Derived1:public BaseClass
{
 public:
      void show() {cout<<"Derived class1"<<endl;}
};
class Derived2:public BaseClass
{
 public:
      void show() {cout<<"Derived class2"<<endl;}
};

int main(){
     BaseClass  obj;
     BaseClass   *p;
     Derived1   obj1;
     Derived2   obj2;
     p=&obj;
     p->show();
     p=&obj1;
     p->show();
     p=&obj2;
     p->show();

    return 0;
}

通过虚函数,达到了用基类指针访问派生类对象成员函数的目的,这样,只要声明了基类指针,就可以使不同的派生类对象产生不同的函数调用,实现了程序的运行时多态。
运行多态应该使用虚函数,并通过指针、引用或者成员函数调用虚函数
          纯虚函数和抽象类

纯虚函数(pure virtual function):

在基类中声明虚拟函数而不给出具体的定义,把它的定义放在各个导出类中,此种函数为纯虚函数

通过基类指针或引用可以调用所有派生类的虚函数。

抽象类:(abstract class)

声明了虚函数的类,基类只用于继承,仅作为一个接口,具体的功能则在派生类中实现。

注意:从抽象类可以派生出具体的或抽象类,但不能从具体类派生出抽象类。

虚基类

虚基类的引入

用于有共同基类的场合

声明

以virtual修饰说明基类例:class B1:virtual public B

作用

主要用来解决多继承时可能发生的对同一基类继承多次而产生的二义性问题.

为最远的派生类提供唯一的基类成员,而不重复产生多次拷贝

类模板

C++中实现多态的另一种方法是类模板

类模板可以使用户为类定义一种模式,使得类中的一些数据成员和成员函数的参数,以及成员函数的返回值能够娶任意类型。

#include <iostream.h>
template <class T> class TestClass {
  public:
     T buffer[10];
          //T类型的数据成员buffer数组大小固定为10 (灵活性差!)
     T getData(int j);       //获取T类型buffer(数组)的第j个分量
};

template <class T>
T TestClass<T>::getData(int j) {
    return *(buffer+j);
};
void main() {
    TestClass<char> ClassInstA;
    //char取代T,从而实例化为一个具体的类
    char cArr[6]="abcde";

    for(int i=0; i<5; i++)
        ClassInstA.buffer[i]=cArr[i];

    for(i=0; i<5; i++) {
        char res=ClassInstA.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
程序执行后的显示结果如下:
a  b  c  d  e
2.1  13.2  24.3  35.4  46.5  57.6 

既使用类型参数又使用 普通参数的类模板示例

#include <iostream.h>
#include "string.h"
template <class T, int i> class TestClass {
  public:
     T buffer[i];
           //T类型的buffer,其大小随普通形参i的值变化(灵活性大!)
     T getData(int j);
};

template <class T, int i>
T TestClass<T,i>::getData(int j) {
    return *(buffer+j);
};
TestClass<double, 6> ClassInstF;
    double fArr[6]={12.1, 23.2, 34.3, 45.4, 56.5, 67.6};
    for(i=0; i<6; i++)
        ClassInstF.buffer[i]=fArr[i]-10;
    for(i=0; i<6; i++) {
        double res=ClassInstF.getData(i);
        cout<<res<<"  ";
    }
    cout<<endl;
}

    程序执行后的显示结果如下:
a  b  c  d  e
2.1  13.2  24.3  35.4  46.5  57.6

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-14 02:12:48

C++重要知识点拾忆的相关文章

从List去除重复拾忆集合

方法1: private static List<int> DistinctList(List<int> list) {//去除重复 HashSet<int> ha = new HashSet<int>(list); list.Clear(); list.AddRange(ha); return list; } 原理:HashSet每次存入会计算哈希值,哈希值相同则比较对方是否相同,不同则直接存入 方法2: private static List<in

基础拾忆------委托详解

目录: 基础拾忆------委托详解 基础拾忆------接口详解 基础拾忆------泛型详解 前言: C# 中的委托(Delegate)类似于 C 或 C++ 中函数的指针.委托是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变.委托(Delegate)特别用于实现事件和回调方法.所有的委托都派生自 System.Delegate 类.把一个方法当作参数传递,让其它方法进行调用执行. 好比:今天中午不想出去,委托小明帮我带份饭,我要买饭,但是小明帮我买的. 1.委托的声明 委托声

基础拾忆------接口详解

目录: 基础拾忆------接口详解 基础拾忆------泛型详解 前言 接口定义了所有类继承接口时应遵循的契约.接口定义了 "要什么" ,派生类定义了 "怎么给" . 引用CLR VIA C#(类和接口继承) 在Microsoft.Net Framwork中,有一个名为System.Object的类,它定义了4个公共实例方法:ToString, Equals, GetHashCode和GetType.该类是其他所有类的根或者说最终基类.换言之,所有类都继承了Obj

程序员修炼之道:从小工到专家--拾忆

第一章 1.关心你的技艺 2.思考!你的工作 3.对自己的代码负责 4.不要找蹩脚的理由 5.不要容忍"破窗户",遇到一个错误的设计或是糟糕的代码,尽量遇一个修一个,一旦这些"破窗户"出现,代码也就会走向腐化 6.观察项目代码的转变 7.使代码质量成为需求问题 8.之道何时止步:不要因为过度修饰和过于求精而毁坏完好的程序,继续前进(5,6并不冲突) 9.定期为你的知识资产投资 9.1.每季度阅读一本技术书籍,也要阅读非技术书籍 9.2.跟上技术潮流(通过博客...)

spring mvc DispatcherServlet详解之拾忆工具类utils

DispatcherServlet的静态初始化 /** * Name of the class path resource (relative to the DispatcherServlet class) * that defines DispatcherServlet's default strategy names. */ private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties&

html结构内容拾忆

文本格式化: 1 <b>This text is bold</b><!--定义粗体文本.--> 2 <strong>This text is strong</strong><!-定义加重语气.--> 3 <big>This text is big</big><!-定义大号字.--> 4 <em>This text is emphasized</em><!-定义着重文字.

using 用法拾忆

using 用法主要包括三种: 1.引用外部命名空间以及外部命名空间中定义的类型(指令) 2.创建命名空间别名,避免因名称相同造成的冲突(指令) 3.定义资源使用范围,在范围结束后释放资源对象(语句) 1. 引用外部命名空间或者类型,允许在在本命名空间内使用引用命名空间类型: using System.IO;using System.Linq;using System.Text; 2.创建命名空间别名,区别相同名称命名空间或类型: using txt= System.Text; using co

jquery实现的网页选项卡(拾忆)

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>网页选项卡</title> <style> *{ margin:0; padding:0;} body { font:12px/19px Arial, Helvetica, sans-serif; color:#666;} .tab { widt

Python拾忆--多线程的socket服务器

阳光明媚的午后,想想最近要开始从写Java到写Python了,就随手打开电脑来体验一下Python与Java之间的不同吧~ 记得我还在上大二的时候,那个时候才开始学Java,最感兴趣的就是Java书最后章节讲的socket套接字那部分,第一次看到同时打开多个黑底白字的shell界面的样子,那么的激动T.T~那个时候还不知道什么是多线程,一个客户端就让其他的客户端不工作了…..那会感觉多线程是我学的最麻烦的地方….那时用了一个下午搞了个多线程的socket程序乐呵呵的玩了好久~~ 要说我最讨厌Py