C++进阶学习(一) 默认参数、成员指针

本文介绍了C++中函数和类成员函数的默认参数使用规则,包括参数顺序、类内外声明以及多态影响。同时,探讨了成员指针的概念,强调它们存储的是偏移地址,并展示了如何通过成员指针调用函数。此外,提到了C++17以后使用<functional>库的invoke函数进行成员访问的便利性。
摘要由CSDN通过智能技术生成

一. 默认参数

  • 函数参数出现缺省参数,位于后面的参数缺省参数必须已被声明

void func1(int, int, int = 10);
void func1(int, int = 6, int);
void func1(int = 4, int, int);

void func1(int a, int b, int c)
{
    cout << a << " " << b << " " << c << endl;
}

void func2(int a = 4, int b = 6)
{
    cout << a << " " << b << endl;
}

int main()
{
    cout << "---begin---" << endl;
    func1();
    func2();
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
4 6 10
4 6
---end---

这种书写方式同样可以应用于类的成员函数中,在类内声明时缺省靠后的参数,在类外实现时缺省靠前的参数

class Test
{
public:
    Test(int, int = 4);
};

Test::Test(int a = 3, int b)
{
    cout << a << " " << b << endl;
}

int main()
{
    cout << "---begin---" << endl;
    Test();
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
3 4
---end---

  • 如果类外的默认参数会使非默认构造函数变为默认构造函数,则程序非良构,应尽量避免这种写法

class Test
{
public:
    Test(int); // 非默认构造
};

Test::Test(int a = 3){} // 缺省后变为默认构造

  • 同时,默认参数应避免类内类外重定义

class Test
{
public:
    Test(int = 4); 
};

Test::Test(int a = 3) {} 

  • 当类实现多态时,子类覆盖函数的默认参数会根据对象的静态类型确定

class Animal
{
public:
    virtual void func(int a = 1)
    {
        cout << "Animal : " << a << endl;
    }
};

class Cat : public Animal
{
public:
    void func(int a = 3) override
    {
        cout << "Cat : " << a << endl;
    }
};

int main()
{
    cout << "---begin---" << endl;
    unique_ptr<Animal> ptr1{new Cat()};
    ptr1->func();
    unique_ptr<Cat> ptr2{new Cat()};
    ptr2->func();
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
Cat : 1
Cat : 3
---end---

对程序进行编译分析时所得到的的表达式类型称为表达式的静态类型,程序执行过程中静态类型将不会改变,在上面的实例中ptr1的静态类型为Animal,动态类型为Cat,而ptr2的静态类型与动态类型都为Cat,故两者调用func时的默认参数不相同。


  • 函数的缺省值不能通过非静态成员变量进行赋值,但静态成员变量可以

class Test
{
    const int n = 3;
    static int t;

public:
    // Test(int a = n); 无法通过非静态成员变量赋值
    Test(int a = t)
    {
        cout << a << endl;
    }
};

int Test::t = 4;

int main()
{
    cout << "---begin---" << endl;
    Test();
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
4
---end---

二、成员指针

  • 数据成员指针或虚函数成员指针不会指向一个内存,而是存储在该类中的偏移地址

  • 成员指针会指向特定的内存,但不能脱离实例对象使用

  • 成员函数指针在声明时需要加上作用域,由实例对象进行调用

class Test
{
public:
    void func(int a)
    {
        cout << a << endl;
    }
};

int main()
{
    cout << "---begin---" << endl;
    void (Test::*print)(int) = &Test::func;
    Test test, *test_ptr = &test;
    (test.*print)(5);
    (test_ptr->*print)(6);
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
5
6
---end---

同样,函数指针也可以作为函数参数

class Test
{
public:
    void func(int a)
    {
        cout << a << endl;
    }
};

void run_func(void (Test::*p)(int), Test &test)
{
    (test.*p)(1);
}

int main()
{
    cout << "---begin---" << endl;
    Test test;
    run_func(&Test::func, test);
    cout << "---end---" << endl;
    return 0;
}

  • 当函数指针作为函数参数时,若存在多个匹配的重载函数时,应使用static_cast来制定调用的函数类型

class Test
{
public:
    void func()
    {
        cout << "void" << endl;
    }

    void func(int a)
    {
        cout << a << endl;
    }
};

void run_func(void (Test::*p)(int), Test &test)
{
    (test.*p)(1);
}

void run_func(void (Test::*p)(void), Test &test)
{
    (test.*p)();
}

int main()
{
    cout << "---begin---" << endl;
    Test test;
    // run_func(&Test::func, test); 存在多个匹配的对象,无法确定调用哪一个
    run_func(static_cast<void (Test::*)(void)>(&Test::func), test);
    run_func(static_cast<void (Test::*)(int)>(&Test::func), test);
    cout << "---end---" << endl;
    return 0;
}

  • 在C++17之后,我们可以使用<functional.h>库中的invoke直接对成员变量与对象进行绑定:当传入数据成员指针时,将会得到一个与对象绑定的引用变量;当传入函数成员指针时,将会对特定对象直接调用该函数

class Test
{
public:
    int a = 1;

    void func()
    {
        cout << "void" << endl;
    }
};

void run_func(void (Test::*p)(int), Test &test)
{
    (test.*p)(1);
}

int main()
{
    cout << "---begin---" << endl;
    Test test;
    int &num = invoke(&Test::a, &test);
    num++;
    cout << test.a << endl;
    invoke(&Test::func, test);
    cout << "---end---" << endl;
    return 0;
}

输出结果:

---begin---
2
void
---end---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值