C++
C++ 类和对象
类class
定义::具有相同属性和行为的对象的集合(人类,就是一个人的集合,每个单独的个体就是这个类的叫对象)
类的基本形式
class 类名
{
public:
//行为或属性
protected:
//行为或属性
private:
//行为或属性
};
类中包含的几个概念:
- 类成员:
类可以没有成员,也可以定义多个成员。成员可以是数据、函数或类型别名。所有的成员都必须在类的内部声明。
没有成员的类是空类,空类也占用空间。 - 成员函数
成员函数必须在类内部声明,可以在类内部定义,也可以在类外部定义。如果在类内部定义,就默认是内联函数。 - 构造函数
构造函数是一个特殊的、与类同名的成员函数,用于给每个数据成员设置适当的初始值。 - 析构函数
析构函数为成员函数的一种,名字与类名相同,在前面加‘~’没有参数和返回值
构造函数与析构函数
注:构造函数可能有多个,但析构函数只能有一个
作用:
- 析构函数
析构函数的作用并不是删除对象,而是在撤销对象占用的内存之前完成一些清理工作
析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比如释放分配的空间等。 - 构造函数
该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作
构造函数的作用:初始化对象的数据成员。
特点
①. 在对象被创建时自动执行;
②. 构造函数的函数名与类名相同;
③. 没有返回值类型、也没有返回值;
④. 构造函数不能被显式调用
语法
构造函数语法:类名(){}
- 构造函数,没有返回值也不写void
- 函数名称与类名相同
- 构造函数可以有参数,因此可以发生重载
- 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次
析构函数语法: ~类名(){}
- 析构函数,没有返回值也不写void
- 函数名称与类名相同,在名称前加上符号~
- 析构函数不可以有参数,因此不可以发生重载
- 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
构造函数的种类
- 实例构造函数
- 静态构造函数
- 私有构造函数
构造函数的显式定义
#include <iostream>
using namespace std;
class Point
{
public:
Point() //声明并定义构造函数
{
cout<<"自定义的构造函数被调用...\n";
xPos = 100; //利用构造函数对数据成员 xPos, yPos进行初始化
yPos = 100;
}
void printPoint()
{
cout<<"xPos = " << xPos <<endl;
cout<<"yPos = " << yPos <<endl;
}
private:
int xPos;
int yPos;
};
int main()
{
Point M; //创建对象M
M.printPoint();
return 0;
}
有参构造函数
#include <iostream>
using namespace std;
class Point
{
public:
Point(int x = 0, int y = 0) //带有默认参数的构造函数
{
cout<<"自定义的构造函数被调用...\n";
xPos = x; //利用传入的参数值对成员属性进行初始化
yPos = y;
}
void printPoint()
{
cout<<"xPos = " << xPos <<endl;
cout<<"yPos = " << yPos <<endl;
}
private:
int xPos;
int yPos;
};
int main()
{
Point M(10, 20); //创建对象M并初始化xPos,yPos为10和20
M.printPoint();
Point N(200); //创建对象N并初始化xPos为200, yPos使用参数y的默认值0
N.printPoint();
Point P; //创建对象P使用构造函数的默认参数
P.printPoint();
return 0;
}
构造函数的重载
Point(int x = 0, int y = 0) //默认参数的构造函数
{
xPos = x;
yPos = y;
}
Point() //重载一个无参构造函数
{
xPos = 0;
yPos = 0;
}
1)实例构造函数
- 构造函数的名字和类名相同
- 有用new表达式创建类的对象或者结构的时,会调用其构造函数,并通常初始化新对象的数据成员
- 除非类是静态的,否则会为没有构造函数的类,自动生成一个默认构造函数
- 构造函数有参数可以以多态的形式存在多个构造函数
2)静态构造函数
- 静态构造函数不使用访问修饰符或不具有参数。
- 在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数以初始化类。
- 不能直接调用静态构造函数。
- 如果静态构造函数引发异常,运行时将不会再次调用该函数,并且类型在程序运行所在的应用程序域的生存期内将保持未初始化。
3)私有构造函数
- 一种特殊的实例构造函数。 它通常用于只包含静态成员的类中。 如果类具有一个或多个私有构造函数而没有公共构造函数,则其他类(除嵌套类外)无法创建该类的实例
创建某个类型的第一个实例时,所进行的操作顺序为:
(1)静态变量设置为0
(2)执行静态变量初始化器
(3)执行基类的静态构造函数
(4)执行静态构造函数
(5)实例变量设置为0
(6)执行衯变量初始化器
(7)执行基类中合适的实例构造函数
(8)执行实例构造函数
注:同样类型的第二个以及以后的实例将从第5步开始执行,因为类的构造器仅会执行一次。此外,第6步和第7步将被优化,以便构造函数初始化器使编译器移除重复的指令。
拷贝构造函数
拷贝构造函数用于从一个已存在的对象创建一个新的对象,即复制构造函数
拷贝构造函数的参数通常是 const 引用类型的对象:
MyClass(const MyClass& other);
析构函数
析构函数
class A
{
private :
char * p;
public:
A ( )
{
p = new char[10];
}
~ A ( )
{
delete [] p;
}
};
调用析构函数的几种情况
- 如果在一个函数中定义了一个对象(它是自动局部对象),当这个函数被调用结束时,对象应该释放,在对象释放前自动执行析构函数。
- static局部对象在函数调用结束时对象并不释放,因此也不调用析构函数,只在main函数结束或调用exit函数结束程序时,才调用static局部对象的析构函数。
- 如果定义了一个全局对象,则在程序的流程离开其作用域时(如main函数结束或调用exit函数) 时,调用该全局对象的析构函数。
- 如果用new运算符动态地建立了一个对象,当用delete运算符释放该对象时,先调用该对象的析构函数。
- 调用复制构造函数后。
静态成员
类对象为静态
注:静态成员不属于对象而是属于类
就像变量一样,对象也在声明为静态时具有范围,直到程序的生命周期。
非静态成员的生命周期
#include<iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x==0)
{
Apple obj;
}
cout << "End of main\n";
}
输出结果
Inside Constructor
Inside Destructor
End of main
静态成员生命周期
#include<iostream>
using namespace std;
class Apple
{
int i;
public:
Apple()
{
i = 0;
cout << "Inside Constructor\n";
}
~Apple()
{
cout << "Inside Destructor\n";
}
};
int main()
{
int x = 0;
if (x==0)
{
static Apple obj;
}
cout << "End of main\n";
}
输出结果
Inside Constructor
End of main
Inside Destructor
静态成员函数
就像类中的静态数据成员或静态变量一样,静态成员函数也不依赖于类的对象。我们被允许使用对象和'.'来调用静态成员函数。但建议使用类名和范围解析运算符调用静态成员。
允许静态成员函数仅访问静态数据成员或其他静态成员函数,它们无法访问类的非静态数据成员或成员函数。
1、静态成员函数类似于静态成员变量都属于类而不是对象。
2、静态成员函数仅可以调用类的静态成员变量,不可以调用普通成员变量。
3、不具有this指针,因而自然不能声明为const。
4、如果类的成员函数想作为回调函数来使用,一般情况下只能将它定义为静态成员才行。
访问静态成员函数
#include<iostream>
using namespace std;
class Apple
{
public:
// static member function
static void printMsg()
{
cout<<"Welcome to Apple!";
}
};
// main function
int main()
{
// invoking a static member function
Apple::printMsg();
}
虚函数
虚函数是在基类中被声明为virtual,并在派生类中重新定义的成员函数,可实现成员函数的动态重载
纯虚函数的声明有着特殊的语法格式:virtual 返回值类型成员函数名(参数表)=0;
构造函数不可以是虚函数,析构函数可以是虚析构函数
虚函数的调用取决于指向或者引用的对象的类型,而不是指针或者引用自身的类型。
纯虚函数
纯虚函数是在基类中声明的虚函数,在基类中没有定义,但要求任何派生类都要定义自己的实现方法。
基类中实现纯虚函数的方法就是在函数的原型后面加“=0”
引入原因:
通俗解释:动物作为一个基类可以派生出老虎、孔雀等子类,但动物本身生成对象明显不合常理
含纯虚函数的类称为抽象类:被继承而不能直接创建对象的类
抽象类是不能定义对象的,在实际中为了强调一个类是抽象类,可将该类的构造函数说明为保护的访问控制权限。
相关规定:
- 抽象类只能用作其他类的基类,不能建立抽象类对象
- 抽象类不能用作参数类型、函数返回类型或显式转换的类型。
- 可以定义指向抽象类的指针和引用,此指针可以指向它的派生类,进而实现多态性。
纯虚函数解释
/**
* @brief
* 抽象类中:在成员函数内可以调用纯虚函数,在构造函数/析构函数内部不能使用纯虚函数
* 如果一个类从抽象类派生而来,它必须实现了基类中的所有纯虚函数,才能成为非抽象类
* @date 2024-07-12
*/
#include <iostream>
using namespace std;
class A {
public:
virtual void f() = 0; // 纯虚函数
void g() { this->f(); }
A() {}
};
class B : public A {
public:
void f() { cout << "B:f()" << endl; }
};
int main() {
B b;
b.g();
return 0;
}
注释:
- 纯虚函数中的对象没有实际功能,通过派生类进行实现。A中的f函数(纯虚函数)没有实际意义,通过派生类B中进行函数功能实现。
- 如果一个类从抽象类派生而来,它必须实现了基类中的所有纯虚函数,才能成为非抽象类。

浙公网安备 33010602011771号