C++

C++练习题

Posted by DEVIN on Sun, Jun 18, 2023

多态

判断

  • Q1: 虚函数可以是内联的? A1: 错误。内联是编译时刻决定的,虚函数是运行时刻动态决定的,所以虚函数不能是内联函数。虚函数前加上inline不会报错,但是会被忽略。

  • Q2: 一个类内部,可以同时声明 static void fun()virutal void fun() 两个函数? A2: 错误。虽然静态函数不存在this指针,但是还是不能声明同参的虚函数和静态函数。

  • Q3: 基类的析构函数非虚,派生类的析构函数是虚函数。delete派生类指针(指向派生类对象)会调用基类析构函数? A3: 正确。

    通过派生类指针,删除派生类对象时,无论父类析构函数是不是虚函数,都会调用基类析构函数。

    通过基类指针,删除派生类对象时,是否调用基类析构函数,取决于基类析构函数是否是virtual函数

知识点

可以通过对象名主动调用析构函数,主动调用构造函数会出错。

如果类中声明了构造函数(无论是否有参数),编译器便不会再为之生成隐含的构造函数。

构造函数不能是虚函数,析构函数可以是虚函数。

编程

析构函数需要声明为virtual

 1#include <iostream>
 2using namespace std;
 3
 4int g_num = 0;
 5
 6class Base
 7{
 8public:
 9    Base() {}
10    ~Base() { g_num += 1; }
11};
12
13class Derived:public Base
14{
15public:
16    Derived() {}
17    ~Derived() { g_num += 2; }
18};
19
20int main()
21{
22    Base *p = new Derived();
23    delete p;
24    cout << g_num << endl;
25    return 0;
26}
27// 输出:1

动态绑定依赖于指针或者引用

 1#include <iostream>
 2using namespace std;
 3
 4class Base
 5{
 6public:
 7    virtual void fun() {cout << "base" << endl;}
 8};
 9
10class Derived:public Base
11{
12public:
13    virtual void fun() { cout << "derived" << endl;}
14};
15
16void func1(Base &obj) {
17    obj.fun();
18}
19void func2(Base obj) {
20    obj.fun();
21}
22
23int main()
24{
25    Base *pBase = new Derived();
26    func1(*pBase); // derived
27    func2(*pBase); // base
28    return 0;
29}

operator可以定义为虚函数

 1#include <iostream>
 2using namespace std;
 3
 4class Base
 5{
 6public:
 7    virtual void operator == (int val2) {
 8        cout << "base: " << val2 << endl;
 9    }
10};
11
12class Derived:public Base
13{
14public:
15    virtual void operator == (int val2) {
16        cout << "derived: " << val2 << endl;
17    }
18};
19
20int main()
21{
22    Base *pBase = new Derived();
23    Derived *pDerived = new Derived();
24    *pBase == 10;
25    *pDerived == 20;
26}
27
28// derived: 10
29// derived: 20

绝不重新定义继承而来的缺省参数

 1#include <iostream>
 2using namespace std;
 3
 4class Base
 5{
 6public:
 7    virtual void fun(string str = "base123") {
 8        cout << str << endl;
 9    }
10};
11
12class Derived:public Base
13{
14public:
15    virtual void fun(string str = "derived") {
16        cout << str << endl;
17    }
18};
19
20int main()
21{
22    Base *pBase = new Derived();
23    pBase->fun(); // base123
24}

同名const函数属于有效重载

 1#include <iostream>
 2using namespace std;
 3
 4class Base
 5{
 6public:
 7    void func1() {cout << "non-const\n";}
 8    void func1() const {cout << "const\n";}
 9};
10
11int main()
12{
13    Base b1;
14    b1.func1(); // non-const。非常量对象也可以调用const函数,此处优先调用non-const函数
15
16    const Base b2;
17    b2.func1(); // const。常量对象只能调用const函数
18}

virtual函数的const必须统一

 1#include <iostream>
 2using namespace std;
 3
 4class Base
 5{
 6public:
 7    virtual void display() const { cout << "Base"; }
 8};
 9
10class Derived:public Base
11{
12public:
13    virtual void display() { cout << "Derived"; }
14};
15
16int main()
17{
18    Base *pBase = new Derived();
19    pBase->display(); // Base
20}

派生类生成过程

派生类构造函数执行顺序:

1.调用基类构造函数,调用顺序按照它们被继承时声明的顺序(从左向右)

2.对派生类新增的成员对象初始化,调用顺序按照它们在类中声明的顺序

3.执行派生类的构造函数体中的内容。

 1#include <iostream>
 2#include <string>
 3using namespace std;
 4
 5class A {
 6public:
 7    A(string name) {cout << name << " ";}
 8};
 9
10class Base {
11public:
12    Base(string str) : a1(str) {}
13public:
14    A a1;
15};
16
17class Derived : public Base {
18public:
19    Derived() : a4("a4"), Base("a1"), a2("a2") {}
20public:
21    A a2;
22    A a3 = A("a3");
23    A a4;
24};
25
26int main()
27{
28    Derived d;
29    return 0;
30}
31// 输出:a1 a2 a3 a4
 1#include <iostream>
 2#include <string>
 3using namespace std;
 4
 5class Base {
 6public:
 7    Base(int val) : a(val) {}
 8protected:
 9    int a;
10};
11
12class Derived : public Base {
13public:
14    Derived(int val1, int val2) : c(val2), Base(val1), b(a + c) {
15        cout << a << " " << b << " " << c << endl; // a==1, b的值不确定, c==10
16    }
17private:
18    int b;
19    int c;
20};
21
22int main()
23{
24    Derived d(1, 10);
25}