C++ перегруженные операторы и перегруженные функции
C++ перегруженные операторы и перегруженные функции
C++ позволяет указывать несколько определений функции и оператора в одной и той же области видимости , что называется перегрузкой функций и перегрузкой операторов соответственно .
Перегруженное объявление — это объявление с тем же именем, что и у функции или метода, уже объявленного в области видимости, но с другим списком параметров и определением (реализацией).
Когда вы вызываете перегруженную функцию или оператор , компилятор решает использовать наиболее подходящее определение, сравнивая используемые вами типы параметров с типами в определении. Процесс выбора наиболее подходящей перегруженной функции или оператора называется разрешением перегрузки .
Перегрузка функций в C++
В одной области видимости несколько функций с одним и тем же именем могут быть объявлены с похожими функциями, но формальные параметры (количество, тип или порядок параметров) у этих функций с одним и тем же именем должны быть разными. Вы не можете перегружать функции, просто различаясь типом возвращаемого значения.
В следующем примере одноименная функция print() используется для вывода разных типов данных:
#include <iostream>
using namespace std;
class printData
{
public:
void print(int i) {
cout << "Printing int: " << i << endl;
}
void print(double f) {
cout << "Printing float: " << f << endl;
}
void print(string c) {
cout << "Printing character: " << c << endl;
}
};
int main(void)
{
printData pd;
// Call print to print integer
pd.print(5);
// Call print to print float
pd.print(500.263);
// Call print to print character
pd.print("Hello C++");
return 0;
}
попробуй
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат:
Printing int: 5
Printing float: 500.263
Printing character: Hello C++
Перегрузка операторов в C++
Вы можете переопределить или перегрузить большинство встроенных операторов C++. Таким образом, вы можете использовать операторы для пользовательских типов.
Перегруженный оператор — это функция со специальным именем, состоящим из ключевого слова operator, за которым следует символ перегружаемого оператора. Как и другие функции, перегруженные операторы имеют тип возвращаемого значения и список параметров.
Box operator+(const Box&);
Объявите оператор сложения, чтобы добавить два объекта Box и вернуть окончательный объект Box. Большинство перегруженных операторов могут быть определены как обычные функции, не являющиеся членами, или как функции-члены класса. Если мы определим вышеуказанную функцию как функцию, не являющуюся членом класса, то нам нужно передать два параметра для каждой операции следующим образом:
Box operator+(const Box&, const Box&);
В следующем примере демонстрируется концепция перегрузки операторов с использованием функций-членов. Здесь объект передается как параметр, а доступ к свойствам объекта осуществляется с помощью оператора this следующим образом:
#include <iostream>
using namespace std;
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength( double len )
{
length = len;
}
void setBreadth( double bre )
{
breadth = bre;
}
void setHeight( double hei )
{
height = hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length; // 长度
double breadth; // 宽度
double height; // 高度
};
// 程序的主函数
int main( )
{
Box Box1; // 声明 Box1,类型为 Box
Box Box2; // 声明 Box2,类型为 Box
Box Box3; // 声明 Box3,类型为 Box
double volume = 0.0; // 把体积存储在该变量中
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3
Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;
}
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат:
Объем коробки 1: 210 Объем Box2: 1560 Объем Box3: 5400
Перегружаемый оператор/неперегружаемый оператор
Ниже приведен список операторов, которые могут быть перегружены:
+ | - | * | / | % | ^ |
& | | | ~ | ! | , | "=" |
< | > | <= | >= | ++ | -- |
<< | >> | == | "=" | && | || |
+= | "=" | "=" | "=" | ^= | "=" |
|= | "=" | <<= | >>= | [] | () |
-> | ->* | новый | новый [] | удалить | удалить [] |
Ниже приведен список неперегружаемых операторов:
:: | .* | . | ?: |
Пример перегрузки оператора
Ниже приведены примеры перегрузки различных операторов, которые помогут вам лучше понять концепцию перегрузки.
Полиморфизм С++
Полиморфизм С++
Полиморфизм буквально означает несколько форм. Полиморфизм используется, когда между классами существует иерархия и классы связаны наследованием.
Полиморфизм C++ означает, что при вызове функции-члена выполняются разные функции в зависимости от типа объекта, вызывающего функцию.
В приведенном ниже примере базовый класс Shape является производным от двух классов следующим образом:
#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};
class Rectangle: public Shape{
public:
Rectangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Rectangle class area :" <<endl;
return (width * height);
}
};
class Triangle: public Shape{
public:
Triangle( int a=0, int b=0):Shape(a, b) { }
int area ()
{
cout << "Triangle class area :" <<endl;
return (width * height / 2);
}
};
// 程序的主函数
int main( )
{
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// 存储矩形的地址
shape = &rec;
// 调用矩形的求面积函数 area
shape->area();
// 存储三角形的地址
shape = &tri;
// 调用三角形的求面积函数 area
shape->area();
return 0;
}
Когда приведенный выше код скомпилирован и выполнен, он дает следующий результат:
Область родительского класса: Область родительского класса:
Причина неправильного вывода в том, что вызывающая функция area() устанавливается компилятором на версию в базовом классе, это называется статическим полиморфизмом или статическим связыванием — вызов функции подготавливается до выполнения программы. Иногда это также называют ранним связыванием , потому что функция area() настраивается во время компиляции программы.
А пока давайте немного изменим программу и поместим ключевое слово virtual перед объявлением area() в классе Shape следующим образом:
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
virtual int area()
{
cout << "Parent class area :" <<endl;
return 0;
}
};
После модификации, когда код предыдущего примера компилируется и выполняется, он дает следующий результат:
Площадь класса прямоугольника Площадь класса треугольника
В этот момент компилятор смотрит на содержимое указателя, а не на его тип. Поэтому, поскольку адреса объектов классов tri и rec хранятся в *shape, вызываются соответствующие функции area().
Как видите, каждый подкласс имеет независимую реализацию функции area(). Вот как обычно используется полиморфизм . С полиморфизмом у вас может быть несколько разных классов, все с функциями с одинаковыми именами, но разными реализациями, и параметры функций могут быть даже одинаковыми.
виртуальная функция
Виртуальная функция — это функция, объявленная в базовом классе с помощью ключевого слова virtual . Когда вы переопределяете виртуальную функцию, определенную в базовом классе, в производном классе, вы указываете компилятору не связываться с этой функцией статически.
Мы хотим, чтобы в любой точке программы мы могли выбирать, какую функцию вызывать, в зависимости от типа вызываемого объекта.Эта операция называется динамической компоновкой или поздней привязкой .
чисто виртуальная функция
Вы можете захотеть определить виртуальную функцию в базовом классе, чтобы переопределение функции в производном классе больше подходило для объектов, но вы не можете дать осмысленную реализацию виртуальной функции в базовом классе.Используйте чисто виртуальные функции.
Мы можем переписать виртуальную функцию area() в базовом классе следующим образом:
class Shape {
protected:
int width, height;
public:
Shape( int a=0, int b=0)
{
width = a;
height = b;
}
// pure virtual function
virtual int area() = 0;
};
= 0 сообщает компилятору, что функция не имеет тела, а приведенная выше виртуальная функция является чисто виртуальной .