C++认识函数

本文介绍了C++中的函数类型,包括成员函数(默认和自定义,如构造、析构、拷贝等)和普通函数,强调了函数的作用域、定义与声明的规则。此外,还讨论了递归函数的使用和限制,以及静态函数的特点。函数指针和类的成员函数指针的使用也被提及,同时提醒了避免二义性问题的方法。
摘要由CSDN通过智能技术生成

C++认识函数


> 函数的种类大概分成两种,成员函数和普通函数,(后面c++11还会有 lambda表达式写的临时函数)
> 函数存放在内存的代码区里,所以在类中不占据空间大小。
> 
> ##成员函数 成员函数又分成默认函数和自定义函数,默认函数前面介绍类的时候有提到,就是构造,析构,拷贝,赋值这几种。\
>         自定义函数就是在函数作用域内声明定义的函数,有虚函数,静态函数,常量函数,内联函数和静态函数。\
>         后面挨个介绍一下这些函数的使用。
> 
> #默认函数:定义类的时候,不用自己定义声明就自动生成的函数。
>         主要功能给类提供一些类的最基本属性,构造,拷贝,赋值,析构。
>         这就能保证类具备了声明,定义,赋值,释放,拷贝的基本功能。
> 
> 有什么基本功能都知道,但是我们因为一些原因,想让一个类不具备这些功能怎么办? 有两种方法: 将想要禁用的默认函数设置成私有

例如
class A
{
    private:
        A(){}
        ~A(){}
        A(const A& a){}
        A& operator=(const A& a) {}
};delete 禁用掉不想要的操作 (c++11的方法)
class A
{
    private:
        A() = delete;
        ~A() = delete;
        A(const A& a)  = delete;
        A& operator =(const A& a) = delete;
};

#自定义成员函数
在类里可以自定义成员函数,除了要清楚的区分出虚函数和其他函数,其他没啥要说的。
基类的虚函数需要用 virtual 来表明,子类不用。\ 
    但是子类最好在声明的时候加上 virtualoverride 关键字,\
    这样可以减少因为手误导致的错误,也增加了代码的可读性。

class A
{
    public:
        virtual void pppddp() = 0;
};

class B : public A
{
    public:
        virtual void pppddp() override; //正确
        virtual void ppddpd() override; // 错误
        virtual void ppddpd(); //正确
};

##普通函数
普通函数和类的成员函数一样,可以把声明和定义分开。
例如:
fun.h:
void p();
fun.cpp:
void p(){}

需要注意的是,如果函数的声明和定义都在头文件里,那么可能会在编译的 过程中带来二义性问题。
head.h:
void p(){}

test.h:
#include "head.h"
void pp();

test.cpp:
#include "test.h"
void pp() {p();}

main.cpp:
#include "test.h"
int main() 
{
    pp();
    return 0;
}
// 链接不过

// 解决这种问题的方式就是通常可以把函数的声明放在.h文件中,定义放在.cpp中,这样就不存在二义性问题。
// 造成这个二义性的原因是,函数可以在不同的文件声明,但是只能定义一次。
// 全局变量不能在.h中定义,应该放在.cpp中,如果定义在.h中,会有二义性问题,因为变量只能生命一次,除非加extern关键字
// 类的成员函数同样有这样的问题,会存在二义性问题
例如:
head.h
class A
{
    public:
        void fun();
};

void A::fun() {};

test.h
#include "head.h"
void p();
test.cpp:
#include "test.h"
void p() {A::fun();}
#include "test.h"
main.cpp:
int main()
{
    p();
    return 0;
}
// 编译不过,存在二义性问题
// 解决方案有2钟,一种是声明定义分开。另一种是把fun()定义成内联函数 

class A
{
    public:
        void fun();
};
inline void A::fun() {}

##函数指针
函数指针和变量的指针差不多意思,都是存储函数的内存地址,\
        因为函数是在代码存储区,所以相同的函数地址相同

格式:
返回值(*指针名) (参数列表)

例如:
int add(int a, int b) {return a + b;}

int(*p) (int,int) = add;
或者
int(*p) (int,int) = &add;
p(100,200); // 300

// 普通函数的函数指针算是好理解,一定要记住的就是,参数列表是独立的,这个是判断是否是一个函数指针的关键
// 但是类的函数指针就不好理解了
格式
返回值 (类名::*指针名) (参数列表)

例如:
class A
{
    public:
        int add(int a, int b) {return a + b;}_
};

//这里必须加取址符
int(A::*p)(int, int) = &A::add;

A a;
(a.*add)(100,200); //必须定义一个类的变量才能调用成员函数指针,并且要加括号把指针名括起来
a.*add(100,2000); // 错误
(a.*)add(100,200); // 错误

// 静态函数
静态函数就是在函数前加 static 。有类的静态函数和普通静态函数。
类的静态函数只能访问静态成员变量,访问非静态的时候会报错
例如
class A
{
    public:
        static int a;
        int b = 10;
        static int c1() {return a;} // 正确
        static int c2() {return b;} // 错误
};

int A::a = 1000;

普通的静态函数会把函数的使用范围限制在本文件中,需要注意的是,静态函数最好定义在.cpp中,要不然就失去了它本身的意义

例如:
test.cpp:
static int p() {return 100;}

main.cpp:
extern int p();
p(); //  拿不到的,肯定会报错


## 递归函数
递归函数就是自己调用自己。递归次数较少的情况下建议使用递归,较多的情况下,不建议,因为会导致堆栈溢出。
操作系统会给每个线程分配一定的函数堆栈,这个堆栈通常不大,大概1M左右。每次调用一次函数,都会压栈一次,
所以调用次数过多就会导致堆栈溢出,但是循环就没有这样的烦恼。
格式:
返回值 函数名 (参数列表)
{
    // 结束标志
    if (...) {
        return xx;
    }

    函数名(参数列表);
}

例如
int fib(int num)
{
    if (num == 1 || num == 2) {
        return 1;
    }

    return fib(num - 1) + fib(num - 2);
}

std::cout << fib(100) << std::endl;

// 斐波那契递归,就是每次上楼梯只能上1个或者2个台阶,又几种方式可以走上去
// 如果台阶是1000000的话,这个函数就会异常了
// 这个时候就建议改成非递归方式
int fib(int num) 
{
    int f1 = 1;
    int f2 = 1;
    int f3 = 1;
    int i = 0;
    for(i = 3;i <= num;i++)
    {
        f3 = f2+f1;
        f1 = f2;
        f2 = f3;
    }
    return f3;
}

// 函数的东西虽然比较少,但是应用确实非常多 // 设计接口是函数最重要的功能之一,也是最麻烦的一部分 //
通常代码逻辑较长的部分都会被拿出来单独起一个函数 // 代码的层次不宜较深,一般超过3层就证明逻辑较乱,需要精炼代码或者提取函数 //
通过函数指针,可以做到成员函数回调的功能 // 后一篇会总结一下函数的用法,这里只要把函数的基本概念搞清楚就行

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小卷同學

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值