嵌入式C++(二)

一、内联函数

1.1 函数调用的回顾

对标C语言中的宏函数
函数的调用有时间和空间上的开销,程序在执行一个函数之前需要做一些工作,实参,局部变量,返回值等若干寄存器入栈,然后才能执行函数体,执行完毕之后,还要回收空间(出栈),等,需要时间和空间上的开销

1.2 c语言中

  • <1> 在复制代码的时候,容易出现意想不到的边界效应

可以使用宏函数来解决中国问题,编译器通过直接替换代码的方式,省去了入栈,出栈等开销,缺点就是缺少
边界的检查,但是在效率上还是可取的
#define MAX(A,B) (A > B) ? A : B

  • <2> 使用宏,无法进行调试
  • <3> 使用宏,无法访问类的私有成员

1.3c++中

推荐使用内联函数代替宏函数,内联函数,类似于宏函数体的替换,这种在函数调用出内嵌入函数体的函数称为内嵌函数,也成为内联函数

inline int myfun(int a,int b)
{
return (a > b)? a: b;
}

<2> 内联函数的特点和缺点

1> 不能存在任何形式的循环语句
2> 不能存在过多的条件判断语句
3> 函数体不能过于庞大(内联函数省去了函数调用时入栈,出栈的等开销)
4> 不能对函数进行取地址操作
5> 函数内联声明必须在调用语句之前
总结:内联函数省去了函数调用时入栈,出栈的等开销,所以当函数体的开销远大于函数的入栈,出栈,跳转
等开销时,内联函数就变得没有意义。

#include <iostream>
using namespace std;
#define MAX(A,B) A > B ? A :B
inline int find_max(int a,int b)
{
return a > b ? a : b;
}
int main(int argc, const char *argv[])
{
int a = 2,b = 2;
cout<<find_max(++a,b)<<endl;
cout<<a<<" "<<b<<endl;
cout<<"***********************"<<endl;
int c = 2,d =2;
int ret = MAX(++c,d); //operator<<(cout,A > B ? A :B)
cout<<"ret = "<<ret<<endl;
return 0;
}

二、c++中默认参数

2.1 概念

​ c++中,允许定义函数参数的时候给其一个默认值,在使用该函数的时候,如果不传参,可以直接使用该默认值

2.2 例

#include <iostream>
using namespace std;
//默认参数在定义的时候,从左往右,只要有一个参数为默认参数,那么它右边所有参数都必须为默认参数
//int MAX(int a,int b = 1,int c) 
int MAX(int a,int b,int c = 100) 
{
	cout<<a<<" "<<b<<" "<<c<<endl;
}
int main(int argc, const char *argv[])
{
	int x = 1,y = 2;
	MAX(x,y);  //如果未传参,直接使用默认参数,如果传参,则使用传的参数
	return 0;
}

三、占位参数

3.1 概念

​ 占位参数只有参数类型的声明,没有参数变量的声明,一般情况下,无法在函数体的内部使用占位参数

3.2 例

#include <iostream>
using namespace std;
struct A
{
	unsigned int a:10;
	unsigned int :20;
	unsigned int c:2;
};
void add(int a,int b,int = 0)  //有时候,占位参数也和默认参数一起使用
{
	cout<<"a + b ="<<a+b<<endl;
}
int main(int argc, const char *argv[])
{
	
	add(1,2);
	cout<<sizeof(A)<<endl;
	return 0;
}

四、函数重载(重点)

4.1 概念

在实际开发的时候,有时候需要实现几个功能类似的函数,在c语言中,不得不定义多个函数名不同的函数去实现它
在c++中,可以利用函数重载,实现一类函数功能,使用同一个函数名实现。

4.2 函数重载的条件

1. 函数名相同
2. 函数的参数 类型,个数,顺序不同
3. 和返回值类型无关

4.3 例

#include <iostream>
using namespace std;
void Swap(int &x,int &y)
{
	cout<<"int int"<<endl;
	int tmp = x;
	x = y;
	y = tmp;
}
/*int Swap(int &x,int &y) //和返回值类型p关
{
	cout<<"int int"<<endl;
	int tmp = x;
	x = y;
	y = tmp;
}*/
void Swap(int &x,double &y)   //参数的类型不同
{
	cout<<"int double"<<endl;
	int tmp = x;
	x = y;
	y = tmp;
}
void Swap(int &x,int &y,int &z)  //参数的个数不同
{
	cout<<"int int int"<<endl;
	int tmp = x;
	x = y;
	y = tmp;
}
void Swap(double &x, int &y)  //参数的顺序不同
{
	cout<<"double int"<<endl;
	int tmp = x;
	x = y;
	y = tmp;
}
int main(int argc, const char *argv[])
{
	int a = 100,b = 200,d = 300;
	double c = 1.2346;
	cout<<"a = "<<a<<" b = "<<c<<endl;
	//Swap(a,b);
	Swap(a,c);
	cout<<"a = "<<a<<" b = "<<c<<endl;
	return 0;
}

五、函数重载的二义性

#include <iostream>
using namespace std;
void add(int a,int b)
{
	cout<<a+b<<endl;
}

void add(int a,int b,int c = 100)
{
	cout<<a+b<<endl;
}
int main(int argc, const char *argv[])
{
	add(1,2);
	return 0;
}

六、c++的动态内存分配

6.1 new /delete

c语言中:使用malloc、free函数
c++中:使用new/delete关键词,但是malloc和free仍然可以使用

6.2 两者区别(*)

c语言:malloc是一个函数,返回值类型是void*类型。

c++中:new和delete是关键词,返回值类型是申请对象的类型,可以初始化。

6.3 例:

#include <iostream>
using namespace std;

int main(int argc, const char *argv[])
{
	int *p = new int;  //分配1个int型的空间,返回值是(int *)
	*p = 100;
	cout<<"*p = "<<*p<<endl;
	delete p; //释放p指向的内存空间
	p = NULL; 

	int *q = new int(200);  //申请1个int,并且对其初始化为200
	cout<<"*q = "<<*q<<endl;
	delete q;
	q = NULL;

	int *q2 = new int[5]{1,2,3,4,5};  //c++11新特性,c++11千不可以初始化动态数组
	for(int i = 0 ; i < 5;i++)
	{
		cout<<q2[i]<<" ";
	}
	cout<<endl;
	delete []q2;
	q2 = NULL;
	return 0;
}

七、多维数组的创建和释放

例:二维数组的动态创建,例如申请存放二维数组int a[3][4]的空间
#include <iostream>
using namespace std;

int main(int argc, const char *argv[])
{
	int **a = new int *[5];
	for(int i = 0 ; i < 5;i++)
	{
		a[i] = new int[6];
	}
	//使用delete进行内存释放,只要将顺序反过来就行
	for(int i = 0 ; i < 5;i++)
	{
		delete []a[i];
	}
	delete []a;
	return 0;
}

练习:

定义一个记录学生信息的结构体,包含姓名,年龄,成绩三个成员,键盘输入5个学生的信息,找到成绩低于平均分的学生,并输出其信息。

八、类和对象

8.1 面向对象编程

优点:

1.开发速度快,如果开发某个功能,实现起来很麻烦的话,可以使用现有的类快速实现
2.封装性和抽象性:结构清晰,很标准,规范化,易于理解,可读性强
3.继承:便于扩展,改动小,大框架不需要改动。
4.易维护:维护成本低。
5.质量高:被反复测试,可以快速的满足各项功能开发的需求
6.效率高:依赖于抽象,对于具体的实现统一了接口

缺点:

相比于c语言,运行效率会下降10%左右。

8.2 类和对象的使用

在这里插入图片描述

#include <iostream>
#include <cstring>
using namespace std;
struct Student   //默认是公有权限
{
    int age;
    char *name;
};

class Student1   //默认是私有权限,只能在类的内部访问
{
public: //声明下面的成员为公有属性
    int age;     //类的成员变量  属性
    char *name;
    void print()  //类的成员函数  方法
    {
        cout<<"age = "<<age<<" name = "<<name<<endl;
    }
};

int main(int argc, char const *argv[])
{
    /*
    Student s1;
    s1.age = 1;
    */
   Student1 s1;
   s1.age = 1;
   s1.name = new char[32];
   strcpy(s1.name,"zhangsan");
   s1.print();
    return 0;
}

8.3 类的访问权限

访问级别由 public protected private 三个关键词组成,在使用三个关键词前,我们首先要了解类的外部和类的内部的概念。
public:公有属性,凡是在它下面定义的,类的内部和外部都可以访问
protected::保护属性,凡是在它下面定义的,在继承关系中,可以在子类中访问
private:私有属性,凡是在它下面定义的,只能在类的内部访问。
#include <iostream>
using namespace std;
class Test
{
private:  //私有属性,只能在类的内部访问
    int a;
    void f1(){}
protected://保护权限,用于继承,类的外部不能访问
    int b;
    void f2(){}
public:  //公有权限,类的内部和外部都可以访问
    int c;
    void f3(){}
private:   //同一个关键词可以出现多次
    int e;
};
int main(int argc, char const *argv[])
{
    Test t1; //Test:类 t1:对象
    //t1.a = 1;  //私有成员不能在类的外部访问
    t1.c = 200;
    return 0;
}

8.4 类中的元素说明

#include <iostream>
using namespace std;
class Circle
{
    private:
        int m_r;  //属性
        double m_s;
    public:
        void SetR(int r) //成员函数 方法
        {
            m_r = r;
        }
        double Gets()
        {
            m_s = 3.14*m_r*m_r;
            return m_s;
        }

};
int main(int argc, char const *argv[])
{
    Circle c1; //创建对象
    c1.SetR(100);
    cout<<c1.Gets()<<endl;
    
    return 0;
}

8.5 类的使用案例

#ifndef _STUDENT_H_
#define _STUDENT_H_
#include <iostream>
using namespace std;
class Student
{
public:
/**
 * @brief Get the Age object
 * 
 * @return int 
 */
    int GetAge();
    int GetID();
    void SetAge(int a);
    void SetID(int i);
private:
    int m_age;
    int m_id;
};
#endif
#include "student.h"

int Student::GetAge()
{
    return m_age;
}
int Student::GetID()
{
    return m_id;
}
void Student::SetAge(int a)
{
    m_age = a;
}
void Student::SetID(int i)
{
    m_id = i;
}
#include "student.h"

int main(int argc, char const *argv[])
{
    Student s1;
    s1.SetAge(18);
    s1.SetID(19);
    cout<<s1.GetAge()<<endl;
    return 0;
}

练习

设计一个圆形类和一个点类,计算点在圆外,园内,还是圆上(点和圆的关系)

1>点:
属性:横坐标和纵坐标
方法:点和点的距离
2>圆:
属性:圆心,半径
方法:设置圆心和半径
      判断点和圆的关系
#ifndef _CIRCLE_H_
#define _CIRCLE_H_

class Point
{
    private:
        int m_x;
        int m_y;
    public:
    void SetXY(int x,int y);
    int Distance(Point &p);
};

class Circle
{
    private:
        Point m_center; //圆心
        int m_r;
    public:
        void setC(int x,int y,int r);
        bool Judge(Point &p);
};
#endif
#include "circle.h"

int main(int argc, char const *argv[])
{
    Point p;
    p.SetXY(0,3);
    Circle c1;
    c1.setC(0,0,3);
    if(c1.Judge(p))
    {
        cout<<"点在圆外或者圆上"<<endl;
    }
    else
    {
        cout<<"点在圆内"<<endl;
    }
    return 0;
}

#include "circle.h"
void Point::SetXY(int x,int y)
{
    this->m_x = x;
    this->m_y = y;
}
int Point::Distance(Point &p)
{
    int dis = (p.m_x - m_x)*(p.m_x - m_x) + (p.m_y - m_y)*(p.m_y - m_y);
    return dis;
}
void Circle::setC(int x,int y,int r)
{
    m_center.SetXY(x,y);
    m_r = r;
}
bool Circle::Judge(Point &p)
{
    if(p.Distance(m_center) >= m_r*m_r)
    {
        return true;
    }
    else
    {
        return false;
    }
}

8.6 对象的构造和析构

8.6.1 构造函数

在c++中,有一种特殊的成员函数,名字和类名相同,没有返回值,不需要用户显示调用(也不能调用),而是在创建对象的时候自动执行.
几点说明:
    1.构造函数的名字和类型必须相同
    2.构造函数不能有返回值,不能有return语句
    3.创建对象的时候自动执行,不能手动调用
    4.主要用于对类的成员进行赋初值。(和初始化有区别)
#include <iostream>
using namespace std;
class Array
{
    private:
        int size;  //数组的容量
        int *data;  //数组首地址
    public:
        Array();  //无参构造函数
        void setVal(int Index,int value);
        int GetVal(int Index);
        ~Array();
};
Array::Array()
{
    cout<<"Array的无参构造函数"<<endl;
    size = 5;
    data = (int *)malloc(sizeof(int)*size);
}
void Array::setVal(int Index,int value)
{
    data[Index] = value;
}
int Array::GetVal(int Index)
{
    return data[Index];
}
Array::~Array()
{
    cout<<"Array的析构函数"<<endl;
    if(data != NULL)
    {
        free(data);
        data = NULL;
    }
}
int main(int argc, char const *argv[])
{
    Array a1; //创建对象,自动调用构造函数
    for(int i = 0 ; i < 5;i++)
    {
        a1.setVal(i,i+1);
    }
    for(int i = 0; i < 5;i++)
    {
        cout<<a1.GetVal(i)<<" ";
    }
    cout<<endl;
    return 0;
}
posted @ 2022-07-05 21:01  周末不下雨  阅读(25)  评论(0编辑  收藏  举报