C++ Primer 知识点复习

1.在C++中简单举例说明什么是动态绑定

动态绑定(也称为运行时绑定)是指在程序运行期间确定要调用的具体函数实现的过程。它是通过虚函数来实现的。当一个函数被声明为虚函数时,它的调用将会被动态绑定。

#include <iostream>
class Animal {
public:
    virtual void speak() {
        std::cout << "Animal speaks!" << std::endl;
    }
};
class Dog : public Animal {
public:
    void speak() override {
        std::cout << "Dog barks!" << std::endl;
    }
};
class Cat : public Animal {
public:
    void speak() override {
        std::cout << "Cat meows!" << std::endl;
    }
};
int main() {
    Animal* animal1 = new Animal;
    Animal* animal2 = new Dog;
    Animal* animal3 = new Cat;
    animal1->speak(); // 输出:Animal speaks!
    animal2->speak(); // 输出:Dog barks!
    animal3->speak(); // 输出:Cat meows!
    delete animal1;
    delete animal2;
    delete animal3;
    return 0;
}

在上面的例子中,我们定义了一个 Animal 类和两个派生类 Dog 和 Cat。Animal 类中有一个虚函数 speak(),在 Dog 和 Cat 类中都重写了该函数。 在 main() 函数中,我们定义了三个指针类型的 Animal 对象,并分别指向了 Animal、Dog 和 Cat 类的对象。然后我们分别调用了它们的 speak() 函数。 这里的关键是,当我们调用 animal2->speak() 和 animal3->speak() 时,实际上调用的是 Dog 和 Cat 类中的 speak() 函数,而不是 Animal 类中的 speak() 函数。这就是动态绑定的实现。

2.在C++泛型算法,用find来解释泛型算法的作用和机理

泛型算法是一种可以适用于不同数据类型的算法,它们不依赖于具体的数据类型,而是通过使用模板来实现通用性。其中,find是一种常用的泛型算法,用于在一个容器中查找指定元素的位置。

find算法的作用是在一个容器中查找指定元素的位置,它可以适用于不同类型的容器,如vector、list、set等。这种通用性使得我们可以在不同的场景中使用同一个算法,从而提高了代码的复用性和可维护性。

find算法的机理是通过迭代器来遍历容器中的元素,然后与指定元素进行比较,直到找到相等的元素或者遍历完整个容器。由于迭代器可以适用于不同类型的容器,因此find算法也可以适用于不同类型的容器。

泛型算法的作用是提供一种通用的算法实现方式,可以适用于不同类型的数据结构,从而提高代码的复用性和可维护性。而find算法则是泛型算法中的一种常用算法,用于在容器中查找指定元素的位置。

find算法接受两个迭代器作为参数,分别表示序列的起始位置和结束位置,以及一个要查找的元素。它会在序列中从起始位置开始逐个比较元素,直到找到第一个与要查找的元素相等的元素,或者到达结束位置。如果找到了相等的元素,find算法会返回该元素的迭代器;否则,它会返回结束位置的迭代器。

以下是一个简单的C++例子,演示如何使用find算法在一个vector中查找指定的元素:

#include <iostream> 
#include <vector> 
#include <algorithm> 
int main() {
 std::vector<int> vec = {1, 2, 3, 4, 5}; 
int target = 3; 
auto it = std::find(vec.begin(), vec.end(), target); 
if (it != vec.end()) { 
std::cout << "Found " << target << " at position " << it - vec.begin() << std::endl; 
} 
else { 
std::cout << "Not found << std::endl;
 } 
return 0; }

在这个例子中,我们定义了一个vector,然后使用find算法在其中查找元素3。如果找到了该元素,我们会输出它在vector中的位置;否则,我们会输出Not found”。需要注意的是,这个例子中的vector只包含整数,但是find算法可以适用于任何类型的序列。

3.友元?为什么需要友元?

友元是一种特殊的关系,它允许一个类或函数访问另一个类的私有成员。友元可以是一个函数、一个类或者一个类的成员函数。需要友元的原因是,有时候需要访问另一个类的私有成员,但是这些成员对外部是不可见的。如果直接访问这些私有成员,编译器会报错。这时候,可以通过友元来解决这个问题。友元理解为一个特权”,它可以访问另一个类的私有成员。但是,友元并不是一个万能的特权”,应该谨慎使用它,避免破坏类的封装性。举个例子,假设我们有一个类A和一个类B,类B需要访问类A的私有成员。我们可以在类A中声明类B为友元,这样类B就可以访问类A的私有成员了。

class A {
 private: 
int x; 
friend class B; // 声明类B为友元 }; 
class B { 
public: void print(A& a) { 
cout << a.x << endl; // 可以访问类A的私有成员x 
}
 };

4.OOP的核心是什么?举例说明。

OOP的核心是将数据和操作数据的方法封装在一起,形成一个对象。这样可以更好地组织和管理代码,提高代码的可重用性和可维护性。举例来说,我们可以创建一个汽车”类,将汽车的属性(如颜色、品牌、型号等)和方法(如启动、加速、刹车等)封装在一起,形成一个汽车对象。这样我们就可以在程序中方便地创建、使用和管理多个汽车对象,而不需要重复编写代码。

C++中OOP的作用是将数据和操作数据的函数封装在一起,形成一个对象,使得程序更加模块化、易于维护和扩展。OOP可以实现以下功能:

封装:将数据和操作数据的函数封装在一起,隐藏内部实现细节,只暴露必要的接口,提高程序的安全性和可靠性。

继承:通过继承可以实现代码的复用,减少代码的重复编写,提高程序的可维护性和可扩展性。

多态:通过多态可以实现同一操作对不同对象的不同响应,提高程序的灵活性和可扩展性。

抽象:通过抽象可以将对象的共性抽象出来,形成类的概念,提高程序的可读性和可维护性。

封装数据结构和算法:通过OOP可以将数据结构和算法封装在一起,形成一个类,提高程序的可读性和可维护性。

5.泛型编程的基础是什么?

C++ 中泛型编程的基础是模板(template)。通过使用模板,我们可以编写通用的代码,以便在不同的数据类型上进行操作,这使得代码更加灵活和可重用。

C++中泛型编程的基础是模板(Template)。模板是一种将类型和值作为参数的函数或类,使得我们可以在编译时根据不同的参数类型或值来生成不同的代码,从而实现一定程度上的代码重用。

下面是一个简单的示例,展示了如何使用模板来实现一个通用的函数,它是一个自定义的通用函数,用于计算数组中元素的总和:

#include <iostream>
using namespace std;
template <typename T>
T sum(T arr[], int n) {
    T s = 0;
    for (int i = 0; i < n; ++i) {
        s += arr[i];
    }
    return s;
}
int main() {
    int arr1[] = {1, 2, 3, 4, 5};
    double arr2[] = {1.1, 2.2, 3.3, 4.4, 5.5};
    cout << "Sum of arr1: " << sum(arr1, 5) << endl;
    cout << "Sum of arr2: " << sum(arr2, 5) << endl;
    return 0;
}

在上面的示例中,sum() 函数是一个模板函数,用于计算数组中元素的总和。该函数使用了一个模板参数 T,这个参数可以表示任何数据类型。在函数体中,我们使用了一个循环来遍历数组中的元素,并将它们相加,最后返回总和。 在 main() 函数中,我们分别定义了两个数组 arr1 和 arr2,并使用 sum() 函数来计算它们的总和。由于 sum() 函数是一个模板函数,因此可以接受不同类型的数组作为参数。

在这个例子中,typename T 表示 T 是一个类型参数。通过使用模板,我们可以编写一个通用的 max 函数,它可以处理任意类型的参数,包括整数、浮点数、字符、字符串等等。例如,以下代码演示了如何使用 max 函数来比较两个整数和两个浮点数:

int main() { 
int x = 3, y = 5;
 cout << "max(" << x << ", " << y << ") = " << max(x, y) << endl;
 double a = 2.5, b = 1.3; 
cout << "max(" << a << ", " << b << ") = " << max(a, b) << endl; 
return 0; }

6.两矩阵的乘积

该程序首先要求用户输入两个矩阵的大小(其中矩阵 A 的大小为 mn,矩阵 B 的大小为 np),然后分别输入这两个矩阵的元素。接下来程序将矩阵 C 的所有元素初始化为 0,然后进行矩阵相乘的操作,并将结果输出到屏幕上。

#include <iostream>
using namespace std;
const int MAXN = 100;
int main() {
    int n, m, p;
    int a[MAXN][MAXN], b[MAXN][MAXN], c[MAXN][MAXN];
    cout << "输入矩阵 A 和 B 的大小 ";
    cin >> n >> m >> p;
    cout << "输入矩阵 A 的元素:\n";
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> a[i][j];
    cout << "输入矩阵 AB的元素:\n";
    for (int i = 0; i < m; i++)
        for (int j = 0; j < p; j++)
            cin >> b[i][j];
    for (int i = 0; i < n; i++)
        for (int j = 0; j < p; j++)
            for (int k = 0; k < m; k++)
                c[i][j] += a[i][k] * b[k][j];
    cout << "Result:\n";
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < p; j++)
            cout << c[i][j] << " ";
        cout << endl;
    }
    return 0;
}

7.定义一个函数,有两个形参,一个是常量字符串,一个是字符。查询字符在常量字符串中第一次出现的位置,找到则返回地址,找不到则返回-1.

#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 100;
int findChar(const char* str, char ch) {
    int len = strlen(str);
    for (int i = 0; i < len; i++) {
        if (str[i] == ch) {
            return i;
        }
    }
    return -1;
}
int main() {
    char str[MAXN];
    char ch;
    cout << "输入一个字符串: ";
    cin.getline(str, MAXN);
    cout << "输入一个字符: ";
    cin >> ch;
    int pos = findChar(str, ch);
    if (pos == -1) {
        cout << "字符没有在字符串中找到.\n";
    } else {
        cout << "字符在字符串中的位置是 " << pos << ".\n";
        cout << "该字符在字符串中的地址是 " << &str[pos] << ".\n";
    }
    return 0;
}

这个程序定义了一个 findChar 函数,用于查询字符在常量字符串中的位置。函数接收两个形参,一个是常量字符串(使用 const char* 声明),一个是字符。函数使用 for 循环遍历整个字符串,如果找到了字符,直接返回位置即可。 最后在 main 函数中调用 findChar 函数,如果返回 -1,则说明字符未找到;否则说明找到了,输出位置和地址即可。

8.查询电话号码地址

①从通讯录phone.txt读取联系人和电话号码,输出格式为联系人 电话1 电话2.

② 用sting流查询联系人的电话号码,将结果保存到multlmap.中

③实现用户交互,输入(cin)联系人,查询联系人的电话号码.

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <map>
using namespace std;
int main() {
    multimap<string, string> phonebook;
    ifstream infile("phone.txt");
    string line;
    while (getline(infile, line)) {
        istringstream iss(line);
        string name, phone1, phone2;
        iss >> name >> phone1 >> phone2;
        phonebook.insert(make_pair(name, phone1));
        if (phone2 != "") {
            phonebook.insert(make_pair(name, phone2));
        }
        cout << name << " " << phone1 << " " << phone2 << endl;
    }
    infile.close();
    string name;
    cout << "输入要查询的姓名: ";
    getline(cin, name);
    auto range = phonebook.equal_range(name);
    if (range.first == phonebook.end()) {
        cout << "在电话簿中没有找到该姓名.\n";
    } else {
        cout << "这个人的电话号码为 " << name << " 是:\n";
        for (auto it = range.first; it != range.second; it++) {
            cout << it->second << endl;
        }
    }
    return 0;
}

这个程序首先打开名为 phone.txt 的文件,逐行读取文件内容,使用 stringstream 将每行内容分解成姓名和电话号码,将姓名和电话号码插入到 multimap 中,并输出到屏幕上。 然后程序提示用户输入要查询的姓名,使用 equal_range 函数在 multimap 中查找该姓名对应的所有电话号码,输出结果到屏幕上。

9.在C++中使用OOP编写管理大学学生和所在社团程序的框架,可以使用类和对象来构建程序。首先,需要定义一个学生类,该类包含学生的基本信息,如姓名、学号、专业、所在社团等。然后,定义一个社团类,该类包含社团的基本信息,如社团名、社团号等。最后,定义一个管理类,该类包含管理学生和社团的方法,如添加学生、删除学生、查询学生信息等。

#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Student {
public:
    string name; //学生姓名
    int id; //学生学号
    string major; //学生专业
    vector<Club*> clubs; //学生所参加的社团列表
    Student(string n, int i, string m) :name(n), id(i), major(m) {} //构造函数
};
class Club {
public:
    string name; //社团名称
    int number; //社团编号
    vector<Student*> members; //社团成员列表
    Club(string n, int num) :name(n), number(num) {} //构造函数
};
class Management {
public:
    vector<Student> students; //所有的学生
    vector<Club> clubs; //所有的社团
    //添加学生
    void add_student(string name, int id, string major) { 
        students.emplace_back(name, id, major);
    }
    //添加社团
    void add_club(string name, int number) { 
        clubs.emplace_back(name, number);
    }
    //学生加入社团
    void enroll(int student_id, int club_number) { 
        students[student_id].clubs.push_back(&clubs[club_number]);
        clubs[club_number].members.push_back(&students[student_id]);
        cout << "学生 " << students[student_id].name << " 成功加入社团 " << clubs[club_number].name << endl;
    }
    //学生退出社团
    void quit(int student_id, int club_number) { 
        bool found = false;
        for (auto i = students[student_id].clubs.begin(); i != students[student_id].clubs.end(); ++i) {
            if ((*i)->number == club_number) {
                found = true;
                students[student_id].clubs.erase(i);
                break;
            }
        }
        if (found) {
            for (auto i = clubs[club_number].members.begin(); i != clubs[club_number].members.end(); ++i) {
                if ((*i)->id == student_id) {
                    clubs[club_number].members.erase(i);
                    break;
                }
            }
            cout << "学生 " << students[student_id].name << " 成功退出社团 " << clubs[club_number].name << endl;
        }
        else {
            cout << "学生并未加入此社团" << endl;
        }
    }
    //删除学生
    void remove_student(int id) { 
        bool found = false;
        for (auto i = students.begin(); i != students.end(); ++i) {
            if (i->id == id) {
                if (!i->clubs.empty()) {
                    cout << "该学生正在参加以下社团:" << endl;
                    for (auto j = i->clubs.begin(); j != i->clubs.end(); ++j) {
                        cout << (*j)->name << endl;
                        quit(i - students.begin(), (*j)->number);
                    }
                }
                students.erase(i);
                found = true;
                cout << "学生 " << id << " 已被删除" << endl;
                break;
            }
        }
        if (!found) {
            cout << "未找到该学生" << endl;
        }
    }
    //查询学生信息
    void print_student_info(int id) { 
        bool found = false;
        for (auto i = students.begin(); i != students.end(); ++i) {
            if (i->id == id) {
                cout << "姓名:" << i->name << endl;
                cout << "学号:" << i->id << endl;
                cout << "专业:" << i->major << endl;
                if (i->clubs.empty()) {
                    cout << "该学生未参加任何社团" << endl;
                }
                else {
                    cout << "参加的社团:" << endl;
                    for (auto j = i->clubs.begin(); j != i->clubs.end(); ++j) {
                        cout << (*j)->name << endl;
                    }
                }
                found = true;
                break;
            }
        }
        if (!found) {
            cout << "未找到该学生" << endl;
        }
    }
    //查询社团信息
    void print_club_info(int number) { 
        bool found = false;
        for (auto i = clubs.begin(); i != clubs.end(); ++i) {
            if (i->number == number) {
                cout << "社团名称:" << i->name << endl;
                cout << "社团编号:" << i->number << endl;
                if (i->members.empty()) {
                    cout << "该社团暂无成员" << endl;
                }
                else {
                    cout << "社团成员:" << endl;
                    for (auto j = i->members.begin(); j != i->members.end(); ++j) {
                        cout << (*j)->name << endl;
                    }
                }
                found = true;
                break;
            }
        }
        if (!found) {
            cout << "未找到该社团" << endl;
        }
    }
};
int main() {
    Management m;
    m.add_student("Tom", 1001, "Computer Science");
    m.add_student("Lucy", 1002, "Mathematics");
    m.add_club("Music Club", 101);
    m.add_club("Sports Club", 102);
    m.enroll(0, 0);
    m.enroll(1, 1);
    m.print_student_info(1001);
    m.print_club_info(101);
    m.quit(0, 0);
    m.remove_student(1002);
    return 0;
}

10.在C++中简单说明动态绑定

动态绑定是指程序在运行时才能确定函数调用的具体过程,也就是说,在编译时无法确定调用哪个函数,而需要根据被调用对象的具体类型来确定调用哪个函数,这种行为被称为动态绑定。在C++中,动态绑定通过虚函数实现,任何具有虚函数的类的某一个函数都是动态绑定的。

11.静态绑定

静态绑定是指程序在编译时就可以确定函数调用的具体过程,根据函数调用表达式中的变量的类型来确定调用那个函数,这样的函数调用被称为静态绑定。比如,在C++中,如果一个函数不是虚函数,则使用的是静态绑定技术。

12.在C++,何谓虚基类,请举例说明

虚基类是指一个基类可以被多次继承。举个例子,假如我们有一个基类A,它有一些基本的功能,接下来有两个派生类B和C,B类和C类分别继承了A,那么就形成了一个虚基类的结构。

下图展示了虚基类的结构:

        A

      /   \

     B     C

虚基类的意义在于,它能够令B和C类共享A类的公共信息,而不需要将A的信息通过继承的方式多次复制到B和C中,从而节约了内存空间。

13.在C++中,在基于TCP的Socket编程中,服务端和客户端的主要流程

1.服务端:

(1)创建套接字:使用socket()函数创建一个TCP套接字;

(2)绑定地址信息:使用bind()函数将套接字与指定的IP地址和端口号进行绑定;

(3)设置最大连接数:使用listen()函数设置最大连接数;

(4)接受连接请求:使用accept()函数接收来自客户端的连接请求;

(5)接收数据:使用recv()函数接收客户端发送的数据;

(6)发送数据:使用send()函数向客户端发送数据;

(7)关闭连接:使用close()函数关闭TCP连接。

2. 客户端:

(1)创建套接字:使用socket()函数创建一个TCP套接字;

(2)发起连接:使用connect()函数向服务端发起连接;

(3)接收数据:使用recv()函数接收服务端发送的数据;

(4)发送数据:使用send()函数向服务端发送数据;

(5)关闭连接:使用close()函数关闭TCP连接。

14.多重继承的概念

多重继承是指一个类可以从多个父类中继承属性和方法。例如,一个类可以从父类A和父类B中继承属性和方法,这就是多重继承。例如: class C : public A, public B { // 属性和方法 };

15.在C++中,举例说明左值引用和右值引用

左值引用是指引用一个可以被赋值的变量,而右值引用是指引用一个不能被赋值的变量。例如: int a = 5;

int &b = a; // b是a的左值引用

int &&c = 5; // c是5的右值引用

16.编写一个模板函数,比较两个模板参数的大小,要求模板实参包括算术类型和类类型,对类对象如何要求?

template <typename T> bool compare(T a, T b) { if (a > b) return true; else return false; } // 对于类类型,需要重载比较函数,以指定比较的方式: class MyClass { public: bool operator>(const MyClass& rhs) const { // 比较的方式 } };

17.++中虚函数应用举例

虚函数是指允许在运行时动态绑定的函数,可以用于实现多态。例如,假设有一个基类Shape,它有一个虚函数draw,它可以被子类Circle、Square等重写,以实现不同的绘图功能: class Shape { public: virtual void draw() = 0; }; class Circle : public Shape { public: void draw() override { // 绘制圆形 } }; class Square : public Shape { public: void draw() override { // 绘制正方形 } };

虚函数是C++中的一种特殊函数,它们可以被子类重写,从而允许多态行为。例如,假设有一个基类Animal,它有一个名为makeNoise()的虚函数。然后可以创建不同类型的动物子类(例如Dog、Cat、Lion),这些子类都可以重写makeNoise()函数来表明每个动物的不同叫声。因此,当使用Animal派生的对象时(例如Dog或Cat对象)并调用makeNoise()时就会得到不同的叫声。

18.以find算法为例,说明算法和容器关系。

find算法是一种用于在容器中搜索元素的通用函数,它可以在任何标准库容器中进行搜索。find()函数的作用就是在一个容器中查找某个特定的元素,如果找到该元素,则返回该元素的位置;如果未找到该元素,则返回end()。

19.find算法中,迭代器如何令算法不依赖容器

使用迭代器可以使find算法不依赖容器,因为迭代器抽象了底层的容器。迭代器提供了一种通用的方式来遍历容器中的元素,而不需要考虑底层的具体实现。因此,使用迭代器可以使find()函数在任何标准库容器中都能够正常工作。C++中泛型函数sort给vector排序,按string长度进行排序

20.C++中函数返回类型和函数指针是什么?请举例说明

函数返回类型是指函数返回的数据类型,例如int、float、char等。函数指针是指指向函数的指针,它可以指向任何函数,例如: int (*func_ptr)(int, int); func_ptr = &add; int result = func_ptr(10, 20);

21.C++中,泛型算法的主要定制操作是什么?请举例说明

C++中的泛型算法的主要定制操作是比较和交换。比较操作是指比较两个元素的大小,交换操作是指交换两个元素的位置。例如,sort()函数就是一个泛型算法,它使用比较和交换操作来对元素进行排序。

22.用序容器vector,关联容器map和set的主要操作,请举例说明。

Vector容器的主要操作有push_back()、pop_back()、insert()、erase()、clear()等。Map容器的主要操作有insert()、erase()、find()、count()、clear()等。Set容器的主要操作有insert()、erase()、find()、count()、clear()等。

23.C++不同对象的生命周期

C++中的对象的生命周期取决于它们的存储位置,具体分为三种:静态存储、自动存储和动态存储。静态存储的对象在程序开始时创建,在程序结束时销毁;自动存储的对象在函数调用时创建,函数返回时销毁;动态存储的对象由程序员使用new操作符创建,使用delete操作符销毁。

24.C++可调用的计算

C++可以调用各种计算,包括算术运算、逻辑运算、位运算、关系运算、条件运算、类型转换等。此外,C++还支持函数调用、类成员函数调用、类成员变量访问等。

C++可以调用的计算包括:算术运算,如加法、减法、乘法、除法等;逻辑运算,如与、或、非等;位运算,如位与、位或、位非等;关系运算,如大于、小于、等于等;条件运算,如if-else、switch-case等;类型转换,如强制类型转换等。

25.C++继承的特征

C++继承的特征包括:一个子类可以继承一个或多个基类;子类可以继承基类的属性和行为;子类可以重写基类的方法;子类可以拓展基类的方法;子类可以拥有自己的属性和行为。例如,假设有一个基类Animal,它有一个方法eat(),那么它的子类Dog可以继承eat()方法,也可以重写eat()方法,比如添加一个新的方法bark(),以拓展Animal类的功能。

26.指针和函数指针

指针是一种特殊的变量,它可以存储另一个变量的地址,从而访问另一个变量的值。函数指针是一种特殊的指针,它可以存储一个函数的地址,从而调用该函数。例如,假设有一个函数int add(int a, int b),那么可以定义一个函数指针int (*p)(int, int),它指向add函数,从而可以通过p调用add函数。

27.基类和派生类

基类是一个父类,它可以定义一些属性和行为,派生类是一个子类,它可以继承基类的属性和行为,并可以拓展基类的功能。例如,假设有一个基类Animal,它有一个方法eat(),那么它的子类Dog可以继承eat()方法,也可以重写eat()方法,比如添加一个新的方法bark(),以拓展Animal类的功能。

  • 33
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值