运算符重载
普通的C++运算符重载成员方法基本都知道,如果没有定义成员方法,那么编译器会优先寻找全局重载运算符看看是否匹配。这里给出了一个使用友元函数和全局重载运算符来实现整数与复数类对象的相加运算。
#include <iostream>
class Complex {
private:
double real;
double imaginary;
public:
Complex(double real = 0.0, double imaginary = 0.0)
: real(real), imaginary(imaginary) {}
double getReal() const {
return real;
}
double getImaginary() const {
return imaginary;
}
// 声明友元函数,operator+可以访问传入的 complex的私有成员
friend Complex operator+(int number, const Complex& complex);
};
// 定义友元函数,实现整数在前的加法运算
Complex operator+(int number, const Complex& complex) {
double newReal = number + complex.real;
return Complex(newReal, complex.imaginary);
}
int main() {
Complex c1(2.0, 3.0);
int number = 5;
Complex result = number + c1;
std::cout << "Result: " << result.getReal() << " + " << result.getImaginary() << "i" << std::endl;
return 0;
}
值得注意的是:双目运算符一般要传两个参数,单目运算符看情况(可能需要传一个参数区分前目和后目)。加法运算符重载和输出运算符(<<)重载都需要两个参数,但它们的参数传递方式不同。对于加法运算符重载,将其定义为成员函数时,左操作数是隐式对象,而右操作数是显式参数。因此,在重载加法运算符时,我们只需要一个显式参数,该参数表示右操作数。对于输出运算符(<<)重载,将其定义为非成员函数时(一般也是如此,因为作为成员函数的时候,默认左操作数是隐式对象,也就是this指针),左操作数是一个输出流对象(std::ostream 类型),而右操作数是要输出的对象。因此,重载输出运算符时需要两个参数。
Iterator
Iterator也叫迭代器,它是一个类中类,更具体来说是容器类内的一个类,这个类有一个属性是指针,指向了容器类元素的地址。它可以提供一种统一的方式,来透明的遍历容器。
#include <iostream>
#include <vector>
int main() {
std::vector<int> myVector = {1, 2, 3, 4, 5};
// 获取迭代器对象
std::vector<int>::iterator it;
// 使用迭代器遍历向量
for (it = myVector.begin(); it != myVector.end(); ++it) {
int element = *it;
std::cout << element << std::endl;
}
return 0;
}
C++11中的foreach方式,本质上也是在用iterator。
#include <iostream>
#include <string>
int main() {
std::string str = "Hello, World!";
// 使用 foreach 循环遍历字符串并打印每个字符
for (char c : str) {
std::cout << c;
}
std::cout << std::endl;
return 0;
}
继承
类和类之间的关系:1、组合,A part of。2、继承,a kind of。
继承的本质是代码的复用。
基类也叫父类,子类也叫派生类。
基类与派生类的关系:
- 基类成员的访问权限,在派生类里面是不能超过继承方式的。
- 外部只能访问对象的public成员,protected和private的成员无法直接访问。
- 在继承结构中,派生类从基类可以继承过来private成员,但是派生类无法直接访问。基类的私有成员对于派生类和外部都是不可见的。
- Protected和private继承的区别是在基类中定义的成员,想被派生类访问,但是不想被外部访问,那么在基类中,把相关成员定义成protected保护的;如果派生类和外部都不打算访问,那么在基类中把相关成员定义成private私有的。
默认的继承方式是什么?要看派生类是class定义的还是struct定义的。Class定义的派生类,默认继承方式是private,否则就是public。
派生类的构造与析构过程
派生类从基类继承来所有的成员。
派生类从基类继承 过来的成员,初始化和清理由基类的构造和析构函数负责。
派生类的构造函数和析构函数,负责初始化和清理派生类部分。
构造的时候会先调用基类的构造函数,析构的时候则相反。
重载、隐藏、覆盖
重载关系:与i组函数要重载,必须要处在同一个作用域当中;而且函数名相同,参数列表不同。
隐藏关系:在继承结构当中,派生类如果有同名成员,把基类的同名成员给隐藏调用了,不管参数列表是否一致。隐藏掉的是作用域,优先找的是派生类自己作用域的show名字成员;没有的话,才去基类里面寻找。如果要调用被隐藏掉的基类成员,需要在函数名前面添加作用域。
一般来说派生类不仅包含了自己带的成员,还包含了基类成员。
所以派生类对象赋值给基类对象的时候,可以直接把基类部分的成员赋值给基类。
基类对象赋值给派生类对象的时候,则不被允许。
基类指针(引用)指向派生类对象的时候,只能访问基类部分的成员。
派生类指针(引用)指向基类对象的时候,则不被允许。有些编译器可能在语法上没问题,但这是不安全的,涉及了内存的非法访问。
覆盖
在C++中,当派生类继承自一个包含虚函数的基类时,派生类会复制基类的虚函数表,从而生成自己的虚函数表。如果派生类重写了虚函数,那么就会修改派生类虚函数表中的虚函数定义,这种关系就叫覆盖。后文再详细说明。