C++ 使用小结

基础:

1.static修饰 
static修饰局部变量,这个局部变量依旧是超出作用域就没办法访问了,但是并没有销毁,依旧存在于内存中,偶尔会用于函数需要返回指针或者引用的时候 ;
static全局变量,限定变量在一个编译单元内,也就是只在某个.h或者某个.cpp文件中才可以访问 
static 修饰普通函数,这个和上一个修饰变量基本类似 


static修饰成员变量,代表这个成员变量是属于整个类的,也就是属于这个类的所有对象。如果某个对象改变了它的值,那么另外的对象也能顺利读取到改变后的值 
static 修饰成员函数,代表函数属于整个类,只能访问static成员变量和其他static成员函数。这里值得注意的一点是static和const不能同时修饰同一个成员函数,因为static成员函数是没有this指针的,因为并不是属于对象。而const的实现方式则是用一个const this指针是调用。

类的静态成员及private修饰的静态成员的使用方法:

- 静态成员变量在类中仅仅是声明,没有定义,所以要在类的外面定义,实际上是给静态成员变量分配内存;

- 静态成员函数和静态数据成员,定义时,不需要加static修饰符,否则会报错:"Cannot declare member function ...to have static linkage";

- public方法访问static成员;static方法只能访问static成员;

- 在pubic方法中,static成员可以用this指针访问(默认隐去this指针);static方法中不能使用this指针。

- private修饰的静态成员函数和静态数据成员,只能在类内部使用;

2.const修饰

3.多态和虚函数 
        多态实现的条件,1.虚函数,2,一个基类指针或者引用指向派生类对象 
具体过程如下: 
       基类指针在调用成员虚函数的时候,就会查找该对象(子类对象)的虚函数表,虚函数表的地址在每个对象的首地址。查找该虚函数表中该函数的指针进行调用。 


PS:每个对象中保存的只是一个指向虚函数表的指针,每个类维护有一个虚函数表(不是每个对象一个虚函数表),该类的所有对象都有一个指针指向这个虚函数表 
       虚函数表在生成的时候,如果子类有覆盖基类的虚函数,那么就会直接覆盖掉基类的虚函数

4.纯虚函数和抽象类

使用:

1.c/c++ 程序结构 ,不允许 函数外对变量进行赋值

函数外对变量进行赋值是不允许的:

//
int i;
i=1;
int main()
{
return 0;
}

可以进行初始化

//
int i=1;
int main()
{
return 0;
}

         在class的成员变量中,也只允许进行初始化,不允许进行赋值;一般不要在头文件中,对类的普通成员变量进行初始化,最好在构造函数中;

         可在成员函数中进行赋值或在构造函数中进行赋值、初始化,const数据成员,除了在定义时进行初始化,也可在构造函数的初始化列表中进行初始化;

        结构体struct定义时,不要对数据进行初始化,有些编译器可能不支持,会报错;

2.C++中,函数不能直接返回多个变量

类似下面的函数,直接return 两个变量c和d;

float _test_func(float a, float b = 1)
{
	float c, d;
	c = a - b;
	d = a + b;
	return c,d;
}

可通过 返回 数组 结构体 或 传入变量的 指针 / 引用 的方式,以达到返回多个变量的目的;

3.带默认参数的函数,不能在函数声明和定义中 同时定义默认参数值,否则,编译时会出现 默认参数重复定义的错误;一般在函数声明中定义默认参数值,定义中不加默认参数

4.条件判断时语法的问题

python中 if (Tarc/2 < t < Tsup - Tarc/2.0),是可以的;在C++中,这样写,会认为是两个 或关系 的条件语句, 

应该写成if (Tarc/2 < t && t < Tsup - Tarc/2.0);

5. 返回值处理

      函数的返回值,一般是用来体现一个函数执行的结果。当调用者需要判断这个结果数据时,就需要用相应类型的变量去接收。若不关心时,允许不去接收、处理它

6.size()和sizeof()

sizeof(a)返回的是对象占用内存的字节数,而a.size()是string类定义的一个返回字符串大小的函数,两个是完全不一样的概念。

明确两者的概念和作用:

-1、size()函数

c++中,在获取字符串长度时,size()函数与length()函数作用相同。 除此之外,size()函数还可以获取vector类型的长度。 

例如:vector < int> num(15,2) ,则:num.size() = 15。

-2、sizeof()

sizeof()运算符用来求对象所占内存空间的大小(字节数);

参数可以是数组、指针、类型、对象、函数等。它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。由于在编译时计算,因此sizeof不能用来返回动态分配的内存空间的大小

数组的长度无法直接通过sizeof()获得;

1.sizeof用于判断数据占据的内存字节数。

如:sizeof(int)的为4。

因此,判断数组的元素个数写法如下:

num=sizeof(array)/size(a[0]);

 

2.判断string类型元素个数

string是字符串,判断字符串中的字符个数

num=string.size();

 

3.判断vector数组的元素个数

vector创建动态数组

num=vector.size();

7. 运行时间测试

#include <time.h>

clock_t start_t = clock();
/*
coding
*/
cout << "<<<< :time consuming = "  << clock() - start_t << endl;

clock()是以ms为单位,要正确输出时间差需要把它换成秒,因此需要除以CLOCKS_PER_SEC

8.在返回值类型为void的函数中可以用return语句

但return后边要为空;

//经常使用retrun空返回来跳出一个函数,比如:
void func()
{
    for(int i=0;i<10;i++)
    {
        if(i==5)
            return; //不等循环结束,直接结束函数
    }
    
}

9. 变量的定义和声明


头文件请不要定义任何变量,那是非常业余的行为
根据C++标准的规定,一个变量声明必须同时满足两个条件,否则就是定义:  
 (1)声明必须使用extern关键字;(2)不能给变量赋初值  ;

extern  int  a;  //声明 
int  a;   //定义
int  a  =  0; //定义
extern  int  a  =0;   //定义

10.C++代码中,对需按C代码进行编译的设置

//头文件中设置
#ifdef __cplusplus
extern "C" {
#endif

/*
*需按C进行编译的相关函数、数据结构定义
*
*/


#ifdef __cplusplus 
}
#endif

11.memcp()的使用

memcpy(dst,src, num*sizeof(int));

使用memcpy时,需要先对dst指向的区域进行内存分配,如果dst只是一个int类型指针,不具有数组指针性质,会报错::段错误 (核心已转储);

12.对函数形参为指针,要判断其值是否为NULL;

13.c语言没有&引用传递,使用&作为函数形参,会编译错误,总提示:少一个")".

C程序,函数不能设置默认参数;

14.#if  #endif  可对代码段动态注释;或者通过检测变量值,自动选择代码段,例如:WIN32和LINUX平台适配

#if 0 //1

/* coding */

#endif

15. 关于代码注释

解释你想做什么(what),和为什么做(why),而不是怎么做的(how)

16.结构体初始化(主要是针对不含成员函数的结构体)

  如:
  struct sample_struct
  {
  char csName[16];
  int iSeq;
  int iType;
  };

1. 定义时直接初始化
  struct sample_strcut stTest = {0}; 

2. 分别赋值
  struct sample_strcut stTest;
  一般情况下,清空stTest的方法:
  stTest.csName[0]='\0';
  stTest.iSeq=0;
  stTest.iType=0;

3. memset可以方便的清空一个结构类型的变量或数组。
  memset(&stTest,0,sizeof(struct sample_struct));

17.类成员函数中的静态局部变量

类成员函数中的静态局部变量同样属于此类该函数,而不属于某个对象

成员函数内的局部变量可以是static的。如果将成员函数内的某个局部变量定义为静态变量,该类的所有对象在调用这个成员函数时将共享这个变量。

class C
{
    public:
        void m();
    private:
        int x;
};
 
void C::m()
{
    static int s=0;
    cout<<++s<<endl;
}
 
int main()
{
    C c1,c2;
    c1.m(); //1
    c2.m(); //2
    c1.m(); //3
    return 0;
}

本例在成员函数m中定义了一个static变量s,由于s定义在程序块内,它拥有程序块范围,
因此它只能在m内部访问。每调用m一次,s就会相应地增加一次。又因为m是C的成员函数,
所以,C的所有对象都共享这个静态局部变量。这样,对m的每一次调用访问的都是同一个s。
相反,对于非静态局部变量x来说,每个C对象都拥有一个x。所以,在main中第一次调用c1.m()
将s从0增加到1,调用c2.m()将s从1增加到2,第二次调用c2.m()将s从2增加到3。

18. 类的三种继承方式

公有继承,私有继承,保护继承。不同的继承方法对派生类的不同作用。


1,派生类 私有继承于基类。

这个时候,派生类继承了基类的公有部分和保护部分,并且继承的这一些数据成员以私有部分存在于派生类中。

基类的私有继承无法访问。

2,派生类 保护继承于基类。

这个时候,派生类继承了基类的公有部分和保护部分,并且基类的公有部分和保护部分都以保护的状态存在于派生类中。

3,派生类 公有继承于基类。

这个时候,派生类继承了基类的公有成员和保护成员,并且, 基类的公有成员还是以公有的状态存在于派生类中,基类的保护成员还是以保护的状态存在于派生类中。


总之,三种继承方式都能集成基类的保护成员和公有成员,三种继承方式都不能访问基类的私有成员,但是不同的继承方式决定了继承的这一些成员在派生类中的不同状态。

然后再就是派生类的构造函数和析构函数    。

首先是派生类的构造函数,有两种情况必须定义构造函数,第一种,派生类需要,第二种,基类的构造函数中含有参数。派生类的参数总表中应包括全部基类和全部内嵌对象的所有参数,还有派生类新增的成员初始化的参数,当派生类属于多重继承时,声明中才会出现多个基类名
Student::Student(char*name,int age, char* classname,char* name1, int age1):Person(name,age), Monitor(name1,age1)
{
    strcpy(ClassName, classname);
}

构造函数的执行顺序.

调用基类构造函数--->调用内嵌对象构造函数--->执行派生类构造函数体中的内容(按照样例就是先执行person,再执行monitor,再执行 student类)。

析构函数的执行顺序

和构造函数相反,先执行派生类构造函数-->内嵌对象构造函数--->基类构造函数。

19.类的const、static、static const数据成员的初始化

const数据成员只能在成员初始化列表进行初始化,static数据成员只能在类外进行初始化,static const数据成员既可以在声明时初始化,也可以在类外初始化。

- - static const的整型(bool,char,int,long)可以在类中声明且初始化;static const的其它类型必须在类外初始化(包括整型数组);

20 数组定义报错:array bound is not an integer constant before 

- 数组的size必须是const int类型,或宏定义, const unsigned int也不行;也不能是非const的变量;

21 Eigen字节对齐问题  

https://blog.csdn.net/derteanoo/article/details/83303760

该问题在编译时不会报错,只在运行时报错。

22.自定义类的初始化

class未初始化 有时会影响很大!,给程序带来各种奇怪的bug;

    BaseController* control;//未初始化!通过getBaseController()对其赋值后,其成员变量仍未初始化
    if(!m_manipulate.getBaseController(control))
与 
    BaseController control;//默认构造函数,会初始化;通过getBaseController()对其赋值后,其成员变量与getBaseController()内保持一致
    if(!m_manipulate.getBaseController(&control))
//指针作为形参,函数内部的操作
bool Manipulate::getKinematic(Kinematic* kinematic)
{
    if (m_init_state)
    {
        kinematic = &m_kinematic;//这种方式,在函数内部,kinematic是指向m_kinematic,但函数外部没有任何改变,因为此处形参kinematic是值传递;
        *kinematic = m_kinematic;//这种方式,在函数外部相应指针也是指向m_kinematic的

        if (!kinematic->get_init_state() )
        {
            vPrintf(">>: Finger init failed ! \r\n");
            return false;
        }
        return true;
    }
    else
    {
        vPrintf(">>ERROR: Please check param init . \n");
        return false;
    } 
}

23. for()中的i++与++i

- 如果只是一条单独语句,没区别,比方说for(i=0;i<9;i++)与for(i=0;i<9;++i)都表示每次f0r循环结束时i+1后判断i是否<9再进入下一次循环。或者是循环内部的i++;及++i;也同理。

- 但如果不是单独语句,就有区别:

比如n=++i;和n=i++;n赋的值就不同,前者n的值为i,i再+1,后者n的值为+1后的i值。

再有把一个数组的值赋到另一个数组中时,y[j++]=x[i];与y[++j]=x[i];也不同 , y数组开始储存的起点不同。

24.mutable关键字

mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。

在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值