目录
一、面向对象的三个核心概念
二、C++语言中的I/O口
三、C++语言中的数据类型
3.1 逻辑类型
3.2 引用类型
3.2.1 引用作为函数参数
3.2.2 引用作为函数返回值
3.2.3 引用作为类成员
3.3 类类型
四、 C++语言中的内联函数
五、 函数重载
六、 带默认形参值的函数
七、 动态内存分配和释放
一、面向对象的三个核心概念
C++语言面向对象的三个核心概念是封装、继承和多态。
-
封装(Encapsulation):封装是一种将数据和操作封装在类中的机制。通过使用类,我们可以将数据和方法绑定在一起,并限制外部访问这些数据和方法。这样可以隐藏实现细节,提高代码的安全性和可维护性。
-
继承(Inheritance):继承是指从一个现有的类派生出一个新的类,新的类称为子类或派生类,原有的类称为父类或基类。子类可以继承父类的成员变量和成员函数,并且可以添加自己的成员变量和成员函数。继承可以实现代码的重用和扩展。
-
多态(Polymorphism):多态是指同一个方法在不同的对象上可以有不同的行为表现。在C++中,多态通过虚函数(virtual function)和纯虚函数(pure virtual function)来实现。通过使用多态,可以在不修改原有代码的情况下,通过派生类对象调用父类的虚函数,实现不同的行为。
这三个核心概念共同构成了C++面向对象编程的基础,可以帮助程序员更好地组织和管理代码,提高代码的可重用性和扩展性。
二、C++语言中的I/O口
在C++语言中,可以通过使用I/O流来实现对I/O口的操作。I/O口是计算机与外部设备之间进行输入输出的接口,它可以用于与键盘、显示器、硬盘、串口等设备进行通信。
在C++语言中,>>符号可以用于两种不同的用途:
- 输入运算符:输入运算符>>用于将数据从输入流(例如键盘)读取到变量中。通常与cin对象一起使用。
- 右移运算符:右移运算符>>用于对二进制数进行右移操作。它会将一个数的二进制表示向右移动指定的位数,并将结果返回。
在C++语言中,<<符号的用途:
- <<符号是一个重载运算符,用于实现输出流的对象插入操作符。它被用于向输出流中插入数据。输出流对象可以使用<<符号连接多个数据,数据会按照从左到右的顺序插入到输出流中。
在C++语言中,可以使用iostream头文件提供的iostream库来操作I/O流。iostream库提供了两个基本的I/O流对象,即cin和cout。
- cin:是一个标准输入流对象,可以用来接收用户的输入。可以使用>>操作符来从标准输入流中读取数据。
int num;
cin >> num; // 从标准输入流中读取一个整数并存储到num变量中
- cout:是一个标准输出流对象,可以用来输出数据到屏幕上。可以使用<<操作符来将数据输出到标准输出流中。
int num = 10;
cout << "The number is: " << num << endl; // 将字符串和变量的值输出到标准输出流中
除了cin和cout,还有cerr和clog这两个标准错误输出流对象,它们用于将错误信息输出到屏幕上。cerr是无缓冲的输出流,而clog是有缓冲的输出流,它们的使用方式和cout类似。
cerr << "Error occurred!" << endl; // 将错误信息输出到标准错误输出流中
需要注意的是,I/O操作是相对较为慢速的操作,因此在进行大量的I/O操作时,应尽量减少不必要的输出,以提高程序执行效率。
三、C++语言中的数据类型
C++语言中的数据类型可以分为基本数据类型、构造数据类型和抽象数据类型。
3.1 逻辑类型
逻辑类型(logic types)指的是能够表示真值(true/false)的数据类型。C++中定义了bool类型来表示逻辑类型,其中true代表真,false代表假。
逻辑类型主要用于表示条件判断和布尔逻辑运算,常用于控制结构的条件表达式中,例如if语句和循环语句。逻辑类型可以通过比较运算符(例如==、!=、<、>等)进行比较,也可以通过逻辑运算符(例如&&、||、!等)进行逻辑运算。
3.2 引用类型
C++语言中的引用类型是指使用引用来操作变量的一种数据类型。引用类型是对已存在的变量起一个别名,通过引用可以直接操作原变量,而不需要通过指针来访问。
C++语言中的引用类型有三种主要的用法:
3.2.1 引用作为函数参数
引用可以用作函数的参数,通过引用传递参数可以直接修改原变量的值,而不需要进行复制。这样可以提高程序的效率,并且避免了不必要的内存消耗。例如:
void swap(int &a, int &b) {int temp = a;a = b;b = temp;
}int main() {int num1 = 10;int num2 = 20;swap(num1, num2);// num1的值现在是20,num2的值现在是10return 0;
}
3.2.2 引用作为函数返回值
函数可以返回引用类型的值,这样可以避免复制大量的数据,而直接返回原变量的引用。需要注意的是,返回引用时,被引用的变量的生命周期必须长于引用的使用,否则可能导致引用悬空的问题。例如:
int& getLarger(int& a, int& b) {if (a > b) {return a;} else {return b;}
}int main() {int num1 = 10;int num2 = 20;int& larger = getLarger(num1, num2);larger = 30;// num2的值现在是30return 0;
}
3.2.3 引用作为类成员
引用可以作为类的成员变量,这样可以在类中直接操作引用所引用的变量,而不需要使用指针。需要注意的是,成员引用必须在类的构造函数中进行初始化,并且一旦初始化后,就不能再引用其他变量。例如:
class Person {
public:Person(string& name) : m_name(name) {}void printName() {cout << m_name << endl;}private:string& m_name;
};int main() {string name = "John";Person person(name);person.printName(); // 输出 "John"return 0;
}
3.3 类类型
类的对象是类类型的实例,可以使用类名后跟一个对象名称创建对象。通过对象可以访问类的成员变量和成员函数。
类类型的对象可以通过构造函数进行初始化,构造函数是一种特殊的成员函数,用于在对象创建时初始化对象的状态。
四、 C++语言中的内联函数
在C++中,内联函数是一种编译器优化技术,用于在函数调用时直接将函数的代码插入到调用者的代码中,而不是通过跳转到函数的地址执行函数体。使用内联函数可以提高程序的执行效率,减少函数调用的开销。
C++中的内联函数通过在函数定义前面加上关键字"inline"来声明。例如:
inline int add(int a, int b) {return a + b;
}
在上面的代码中,add函数被声明为内联函数。当调用add函数时,编译器会将函数体直接插入到调用者的代码中,而不是跳转到add函数的地址执行。
C++中的内联函数通过在函数定义前加上关键字"inline"来声明,用于提高程序的执行效率。适用于简单、短小的函数,通常定义在头文件中。
五、 函数重载
函数重载是指在一个程序中可以有多个同名函数,但这些函数的参数类型、参数个数或参数顺序不同。当调用这个函数时,编译器会根据参数的类型、个数和顺序来确定具体调用的是哪个函数。函数重载可以提高程序的灵活性和可读性,使代码更加简洁和优雅。
在C++中,函数重载是通过函数的参数列表来实现的。
例如,下面是两个同名函数的定义:
void print(int num) {cout << "The number is: " << num << endl;
}void print(string text) {cout << "The text is: " << text << endl;
}
这两个函数都叫做print,但参数类型不同,第一个函数接受一个int类型的参数,第二个函数接受一个string类型的参数。
当调用这个print函数时,编译器会根据传入的参数的类型来确定具体调用的是哪个函数。例如:
print(10); // 调用print(int num)
print("Hello"); // 调用print(string text)
这样,就可以根据不同的参数类型来选择调用不同的函数,实现函数的重载。
六、 带默认形参值的函数
C++中可以定义带有默认参数值的函数。默认参数值是指在函数声明或定义时给函数参数赋予一个默认值,如果在函数调用时未提供实际参数,则会使用默认值。
下面是一个带有默认参数值的函数的例子:
void printMessage(string message = "Hello, World!") {cout << message << endl;
}
在上面的例子中,函数printMessage有一个字符串类型的参数message,并给它赋予了默认值"Hello, World!"。
当调用printMessage函数时,可以选择提供实际参数来覆盖默认值,或者不提供实际参数使用默认值。例如:
printMessage(); // 输出: Hello, World!
printMessage("Goodbye!"); // 输出: Goodbye!
在第一个调用中,由于没有提供实际参数,所以函数使用了默认值"Hello, World!"。在第二个调用中,提供了实际参数"Goodbye!",覆盖了默认值。
需要注意的是,带有默认参数值的参数必须放在参数列表的末尾,不能跳过某个参数给后面的参数赋予默认值。例如:
void printNumbers(int a, int b = 0, int c) {cout << a << ", " << b << ", " << c << endl;
}
上面的函数定义是错误的,因为默认参数值必须是在参数列表的末尾。应该将参数c放在默认参数值的前面,才能正确使用默认参数。
七、 动态内存分配和释放
C++中的动态内存分配和释放是通过new和delete关键字来实现的。
使用new关键字可以在堆上分配一块指定类型的内存,并返回其地址。我们可以将此地址赋值给一个指针变量,以便后续访问和使用。
例如,以下代码演示了如何使用new动态分配一个int类型的内存块:
int* p = new int;
上述代码将分配一块int类型的内存,并将其地址赋值给指针变量p。
使用delete关键字可以释放之前通过new分配的内存。释放内存后,我们就不能再访问被释放的内存块,否则会导致未定义行为。
例如,以下代码演示了如何使用delete释放之前分配的int类型内存块:
delete p;
上述代码将释放之前通过new分配的int类型的内存块。
注意:
使用new分配的内存必须使用delete进行释放,否则会导致内存泄漏。同时,释放已经释放过的内存或堆栈上的内存也会导致未定义行为。
另外,还可以使用new[]和delete[]关键字来分配和释放一维动态数组的内存。例如:
int* arr = new int[5];
delete[] arr;
上述代码将分配一个包含5个int类型元素的动态数组,并在使用完后通过delete[]释放内存。
注意:
使用new[]分配的数组内存必须使用delete[]进行释放,否则会导致内存泄漏。同样,释放已经释放过的内存或堆栈上的内存也会导致未定义行为。