C++面向对象
一、类
1.1类&对象
class classname//class是关键词,classname是类名
{
Access specifiers://访问修饰符:private/public/protected
Date members/variables;//变量
Member functions(){}//方法
};//分号结束一个类
【例】定义Box类
class Box//盒子
private:
double length;//长
double breadth;//宽
double height;//高
//成员函数声明
public:
tuple< double,double,double>GetMessage();//获取盒子信息
void set(double len,double bre,double hei);//修改盒子信息
}
};
tuple< double,double,double> Box::GetMessage(){
return {length,breadth,height};
}
void Box::set(double len,double bre,double hei){
length=len;
breadth=bre;
height=hei;
}
访问类的成员函数:
Box Box1;
Box1.GetMessage();//此处有省略,应当有构造函数,下面介绍
1.2类成员函数
成员函数的作用:
类的成员函数只属于该类,是类的一个成员,它可以访问类的成员,对具体的对象进行操作(private修饰的成员变量只能由成员函数进行修改)
成员函数的定义:
成员函数可以定义在类定义内部,或单独使用范围解析运算符::定义
如:
tuple< double,double,double> Box::GetMessage(){
return {length,breadth,height};
1.3类访问修饰符
public成员:在类的外部可以访问,不需要通过成员函数设置和获取共有变量的值
private成员:在类的外部不可访问,只有该类和友元函数可以访问私有成员
protected成员:与private成员相似,但是protected成员可以在派生类(子类)中访问
三种继承方式:
public继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了public,protected,private
protected继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了protected,protected,private
private继承:基类public成员、protected成员、private成员的访问属性在派生类中分别变成了private,private,private
1.4构造函数&析构函数
#include< iostream>
using namespace std;
class Line
{
public:
void setLength(double len);
double getLength(void);
Line();//不带参数的构造函数
Line(double len);//带参数的构造函数
~Line();//析构函数
private:
double length;
};
Line::Line(void){
cout<<"Object is being create"<< endl;
}
Line::Line(double len){
cout<<"Object is being create,length= "<< len<< endl;
}
Line::~Line(void){
cout<<"Object is being deleted"<< endl;
}
void Line::setLength(double len){
length=len;
}
double Line::getLength(void){
return length;
}
int main(){
Line line;
line.setLength(6.0);
cout<<"Length of line : "<< line.getLength()<< endl;
return 0;
}
//编译上述代码并执行产生下面结果:
//Object is being created
//Length of line : 6
//Object is being deleted
1.5拷贝构造函数
拷贝构造函数属于构造函数,如果类带有指针变量并有动态内存分配,它在创建对象时,使用同一类中之前创建的对象来初始化新创建的对象。通常用于:
- 同一个同类型的对象初始化新对象(=赋值)
- 复制对象把它作为参数传递给函数
- 复制对象,并从函数返回这个对象
常见形式:
classname (const classname &obj){……}//obj是一个对象的引用,用于初始化另一个对象
【例】拷贝构造函数——此处省略class的其他函数,只展示拷贝构造函数的定义以及用法
Line::Line(const Line &obj)
{
cout << "调用拷贝构造函数并为指针 ptr 分配内存" << endl;
ptr = new int;
*ptr = *obj.ptr; // 拷贝值
}
// 程序的主函数
int main( )
{
Line line(10);
Line line2=line1;
print(line);
return 0;
}
1.6友元函数
类的友元函数在类的定义中声明,但不是成员函数。友元函数定义在类外部,有权访问类的所有private成员和protected成员。
友元可以是函数(友元函数),也可以是类(友元类)
如:
friend void printWidth(Box box);
friend class ClassTwo;
【例】友元函数
class Box
{
double width;
public:
friend void printWidth( Box box );
void setWidth( double wid );
};
// 请注意:printWidth() 不是任何类的成员函数
void printWidth( Box box )
{
/* 因为 printWidth() 是 Box 的友元,它可以直接访问该类的任何成员 */
cout << "Width of box : " << box.width <<endl;
}
printWidth( box );
1.7内联函数
函数名前有关键字inline的函数为内联函数,内联函数在编译时,编辑器会把该函数的代码副本放置在每个调用该函数的地方。类定义中定义的函数都是内联函数
1.8this指针
this是一个隐藏的指针,可以在类的成员函数中使用,用来指向当前调用对象(当一个对象的成员函数被调用时,编辑器会隐式地传递该对象的地址作为this指针)。友元函数没有this指针,因为友元不是类的成员,只有成员函数才有this指针
例如:
int compare(Box box)
{
return this->Volume() > box.Volume();
}
Box1.compare(Box2);
1.9指向类的指针
一个指向 C++ 类的指针与指向结构的指针类似,访问指向类的指针的成员,需要使用成员访问运算符 ->
常见操作:
1. MyClass obj;
MyClass *ptr=&obj;//指向对象
2. MyClass *ptr=new MyClass;//动态分配
3. void processObject(MyClass *ptr){ptr->display():}//作为函数参数传递
1.10类的静态对象
使用static关键字把类成员定义为静态时,无论创建多少个类的对象,静态成员变量只有一个副本(静态成员在类的所有对象中是共享的)。不能把静态成员变量的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符::重新声明静态变量从而对它进行初始化
静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。
静态成员函数没有this指针,只能访问静态成员(包含静态成员变量和静态成员函数)。静态函数即使在类对象不存在的情况下也能被调用,只要使用classname::即可访问
练习实例——点击跳转(笔者本人应用知识点写的代码)
二、继承
2.1派生类
基本形式:class derived_class:access_specifier base_class。其中derived_class是派生类名,access_specifier 是public\protected\private中的一个,base_class是基类名。例如:class Dog:public Animal{};
// 基类
class Shape {
protected:
int width;
int height;
};
// 派生类
class Rectangle: public Shape {
public:
int getArea() {
return (width * height);
}
};
派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。
2.2多继承
class <派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{
<派生类类体>
};
如
class A: public B, public C{……};
三、重载运算符和重载函数
C++允许在同一个作用域中函数和运算符有多个定义(参数列表不同)——函数重载和运算符重载。
3.1函数重载
重载的同名函数形参必须不同(参数的个数、类型或者顺序)。如:
void print(int i) {
cout << "整数为: " << i << endl;
}
void print(double f) {
cout << "浮点数为: " << f << endl;
}
void print(char c[]) {
cout << "字符串为: " << c << endl;
}
3.2运算符重载
基本形式:< return > operator < op>(parameter)
点击运算符可查看重载代码
一元运算符 | 递增运算符++,递减运算符--,负号-,逻辑非! |
二元运算符 | 加+,减-,乘*,除/ |
关系运算符 | < , > , <= , >= , == |
输入/输出运算符 | << , >> |
赋值运算符 | = |
函数调用运算符 | () |
下标运算符 | [] |
类成员访问运算符 | -> |
四、多态
4.1虚函数
- 在基类声明一个虚函数(关键字为virtual)
- 派生类可以重写虚函数
- 调用虚函数时,会根据对象的实际类型决定调用哪个版本的函数
class Animal {
public:
virtual void sound() { // 虚函数
cout << "Animal makes a sound" << endl;
}
};
class Dog : public Animal {
public:
void sound() override { // 重写虚函数
cout << "Dog barks" << endl;
}
};
4.2动态绑定
- 在运行时决定函数调用的具体实现
- 需要使用指向基类的指针或引用来调用虚函数,运行时根据对象的类型决定调用哪个函数
Animal *animal = new Dog();
animal->sound(); // 输出: Dog barks
4.3纯虚函数
当想要在基类中定义虚函数,但又不能对虚函数给出有意义的实现,这是会用到纯虚函数
- 一个包含纯虚函数的类被称为抽象类,不能被直接实例化
- 纯虚函数没有函数体 ,声明时使用=0
- 强制派生类提供具体的实现
class Shape {
public:
virtual int area() = 0; // 纯虚函数,强制子类实现此方法
};
class Rectangle : public Shape {
private:
int width, height;
public:
Rectangle(int w, int h) : width(w), height(h) { }
int area() override { // 实现纯虚函数
return width * height;
}
};
4.4多态的实现机制
- 虚函数表:C++运行时使用虚函数表来实现多态,每个包含虚函数的类都有一个虚函数表,表中存储了指向类中所有虚函数的指针
代码示例
#include<iostream>
#include<tuple>
using namespace std;
class Box {
private:
int hei;
int len;
int bre;
Box* next;
static int num;
public:
Box();//不带参数的构造函数
Box(int hei, int len, int bre, Box* next = NULL);//带参数的构造函数
Box(const Box& box);//拷贝构造函数(浅拷贝&深拷贝)
~Box();//析构函数
void set(int hei, int len, int bre, Box* next = NULL);
tuple<int, int, int, Box*>GetMessage();
int Volume();
friend void print(const Box& box);
};
int Box::num = 0;//初始化静态变量
int main() {
Box box(1, 1, 1);
cout << "box的体积为" << box.Volume() << endl;
print(box);
return 0;
}
Box::Box():hei(0),len(0),bre(0),next(NULL) {
num++;
cout << "Block box is being created" << endl;
}
Box::Box(int hei, int len, int bre, Box* next) :hei(hei), len(len), bre(bre), next(next) {
num++;
cout << "A box is being created, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}
Box::Box(const Box& box) {
num++;
hei = box.hei;
len = box.len;
bre = box.bre;
next = new Box;
*next = *box.next;
cout << "A box is being created, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}
Box::~Box() {
cout << "A box is being deleted, whose hei is " << hei << " ,len is " << len << " and bre is " << bre << endl;
}
void Box::set(int hei, int len, int bre, Box* next) {
this->hei = hei;
this->len = len;
this->bre = bre;
this->next = next;
}
tuple<int, int, int, Box*> Box::GetMessage() {
return { hei,len,bre ,next };
}
int Box::Volume() {
return hei * len * bre;
}
void print(const Box& box) {
cout << "This box message is :" << "height(" << box.hei << ")" << " " << "length(" << box.len << ")" << " " << "breadth(" << box.bre << ")" << endl;
}
成员函数:ReturnType operator-() const{……}
全局函数:ReturnType operator-(const ClassType&obj){……}
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
// 前置递增 ++obj
Counter& operator++() {
++count; // 先递增
return *this; // 返回当前对象的引用
}
int getCount() const { return count; }
};
int main() {
Counter c(5);
++c; // 调用 operator++()
std::cout << c.getCount(); // 输出 6
}
前置递增++obj重载(全局函数)
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
friend Counter& operator++(Counter& c); // 声明友元
int getCount() const { return count; }
};
// 全局前置 ++
Counter& operator++(Counter& c) {
++c.count;
return c;
}
后置递增obj++重载(成员函数)
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
// 后置递增 obj++
Counter operator++(int) {//int是占位参数,用于区分前置和后置
Counter temp = *this; // 保存当前值
++count; // 递增
return temp; // 返回旧值
}
int getCount() const { return count; }
};
int main() {
Counter c(5);
Counter old = c++; // 调用 operator++(int)
std::cout << old.getCount(); // 输出 5(旧值)
std::cout << c.getCount(); // 输出 6(新值)
}
后置递增obj++重载(全局函数)
class Counter {
private:
int count;
public:
Counter(int c = 0) : count(c) {}
friend Counter operator++(Counter& c, int); // 声明友元
int getCount() const { return count; }
};
// 全局后置 ++
Counter operator++(Counter& c, int) {
Counter temp = c;
++c.count;
return temp;
}
跳转返回——多态
负号-
成员函数重载:
class Number {
private:
int value;
public:
Number(int v) : value(v) {}
// 一元减运算符重载(成员函数)
Number operator-() const {
return Number(-value);
}
int getValue() const { return value; }
};
int main() {
Number n(5);
Number neg = -n; // 调用重载的一元减运算符
std::cout << neg.getValue(); // 输出 -5
}
全局函数重载:
class Number {
private:
int value;
public:
Number(int v) : value(v) {}
int getValue() const { return value; }
};
// 一元减运算符重载(非成员函数)
Number operator-(const Number& num) {
return Number(-num.getValue());
}
int main() {
Number n(10);
Number neg = -n; // 调用重载的一元减运算符
std::cout << neg.getValue(); // 输出 -10
}
跳转返回——多态
加+
成员函数重载
class Box {
private:
int hei, len, bre;
public:
// ...(其他成员函数和构造函数)
// 成员函数重载 +
Box operator+(const Box& other) const {
return Box(
hei + other.hei, // 高度相加
len + other.len, // 长度相加
bre + other.bre // 宽度相加
);
}
};
全局函数重载
class Box {
private:
int hei, len, bre;
public:
// ...(构造函数和其他成员函数)
// 声明友元,让全局函数能访问私有成员
friend Box operator+(const Box& lhs, const Box& rhs);
};
// 全局函数重载 +
Box operator+(const Box& lhs, const Box& rhs) {
return Box(
lhs.hei + rhs.hei,
lhs.len + rhs.len,
lhs.bre + rhs.bre
);
}
跳转返回——多态
等于==
成员函数
class Box {
private:
int hei, len, bre;
public:
// ...(其他成员函数和构造函数)
// 成员函数重载 ==
bool operator==(const Box& other) const {
return (hei == other.hei) &&
(len == other.len) &&
(bre == other.bre);
}
};
全局函数
class Box {
private:
int hei, len, bre;
public:
// ...(构造函数和其他成员函数)
// 声明友元,让全局函数能访问私有成员
friend bool operator==(const Box& lhs, const Box& rhs);
};
// 全局函数重载 ==
bool operator==(const Box& lhs, const Box& rhs) {
return (lhs.hei == rhs.hei) &&
(lhs.len == rhs.len) &&
(lhs.bre == rhs.bre);
}
跳转返回——多态
输入>>
全局函数
#include <iostream>
using namespace std;
class Box {
private:
int hei, len, bre;
public:
// 声明友元函数,允许访问私有成员
friend istream& operator>>(istream& is, Box& box);
};
// 全局函数重载 >>
istream& operator>>(istream& is, Box& box) {
is >> box.hei >> box.len >> box.bre; // 按顺序读取长、宽、高
return is; // 返回输入流以支持链式调用(如 cin >> box1 >> box2)
}
跳转返回——多态
赋值=
class Box {
private:
int hei, len, bre;
Box* next; // 假设包含动态分配的资源
public:
// ...(其他成员函数和构造函数)
// 重载赋值运算符 =
Box& operator=(const Box& other) {
if (this != &other) { // 防止自赋值(如 a = a)
hei = other.hei;
len = other.len;
bre = other.bre;
// 深拷贝 next(如果存在)
if (next != nullptr) {
delete next; // 释放原有资源
next = nullptr;
}
if (other.next != nullptr) {
next = new Box(*other.next); // 深拷贝
}
}
return *this; // 返回当前对象的引用
}
};
跳转返回——多态
函数调用运算符()
#include <iostream>
using namespace std;
class Adder {
int value;
public:
Adder(int v) : value(v) {}
// 重载函数调用运算符
int operator()(int x) {
return value + x;
}
};
int main() {
Adder add5(5); // 创建一个Adder对象,初始值为5
cout << add5(10) << endl; // 像函数一样调用,输出15
cout << add5(20) << endl; // 输出25
return 0;
}
跳转返回——多态
下标运算符[]
#include <iostream>
#include <vector>
using namespace std;
class IntArray {
vector<int> data;
public:
IntArray(size_t size) : data(size) {}
// 非常量版本,允许修改
int& operator[](size_t index) {
if (index >= data.size()) {
throw out_of_range("Index out of range");
}
return data[index];
}
// 常量版本,只读访问
const int& operator[](size_t index) const {
if (index >= data.size()) {
throw out_of_range("Index out of range");
}
return data[index];
}
size_t size() const { return data.size(); }
};
int main() {
IntArray arr(5);
// 使用[]赋值
for (size_t i = 0; i < arr.size(); ++i) {
arr[i] = i * 10;
}
// 使用[]读取
for (size_t i = 0; i < arr.size(); ++i) {
cout << arr[i] << " ";
}
// 输出: 0 10 20 30 40
// 常量对象使用
const IntArray carr(3);
cout << carr[0]; // 使用const版本
return 0;
}
跳转返回——多态
类成员访问运算符->
#include <iostream>
using namespace std;
class Data {
public:
int value;
Data(int v) : value(v) {}
void print() { cout << "Value: " << value << endl; }
};
class DataPtr {
Data* ptr;
public:
DataPtr(Data* p) : ptr(p) {}
~DataPtr() { delete ptr; }
// 重载->运算符
Data* operator->() { return ptr; }
const Data* operator->() const { return ptr; }
};
int main() {
DataPtr dp(new Data(42));
dp->print(); // 实际调用: dp.operator->()->print()
dp->value = 100; // 访问成员变量
const DataPtr cdp(new Data(200));
cdp->print(); // 使用const版本
return 0;
}
#include <iostream>
using namespace std;
// 基类 Shape,表示形状
class Shape {
protected:
int width, height; // 宽度和高度
public:
// 构造函数,带有默认参数
Shape(int a = 0, int b = 0) : width(a), height(b) { }
// 虚函数 area,用于计算面积
// 使用 virtual 关键字,实现多态
virtual int area() {
cout << "Shape class area: " << endl;
return 0;
}
};
// 派生类 Rectangle,表示矩形
class Rectangle : public Shape {
public:
// 构造函数,使用基类构造函数初始化 width 和 height
Rectangle(int a = 0, int b = 0) : Shape(a, b) { }
// 重写 area 函数,计算矩形面积
int area() override {
cout << "Rectangle class area: " << endl;
return width * height;
}
};
// 派生类 Triangle,表示三角形
class Triangle : public Shape {
public:
// 构造函数,使用基类构造函数初始化 width 和 height
Triangle(int a = 0, int b = 0) : Shape(a, b) { }
// 重写 area 函数,计算三角形面积
int area() override {
cout << "Triangle class area: " << endl;
return (width * height / 2);
}
};
// 主函数
int main() {
Shape *shape; // 基类指针
Rectangle rec(10, 7); // 矩形对象
Triangle tri(10, 5); // 三角形对象
// 将基类指针指向矩形对象,并调用 area 函数
shape = &rec;
cout << "Rectangle Area: " << shape->area() << endl;
// 将基类指针指向三角形对象,并调用 area 函数
shape = &tri;
cout << "Triangle Area: " << shape->area() << endl;
return 0;
}