C++ (5)
5. 类
5. 1 访问控制
- public;在类的外部可见,并可被调用和操作。
- private:只能被该类的成员函数访问。
- protected:只能被该类的函数和派生类的函数访问。
※ 这三个关键字后面都可以跟一大串声明。
- friend:不属于类的成员函数,但可以像类的成员一样访问类的 private 和 protected 成员,可以是一个类或者一个函数。
- virtual:虚拟函数。
※ 这两个关键字后面都只能用于一条声明。
5. 2 构造函数
使用默认参数的构造函数,即使在调用构造函数时没有提供实参时不会出错,还可以按照默认参数值对对象进行初始化。
#include <iostream> using namespace std; class Box { public: Box ( int h = 10, int w = 10 ,int len = 10); int volume( ); private: int height; int width; int length; }; Box:Box ( init h, int w, int len ) { height = h; width = w; length = len; } int Box:volume() { return ( height*width*length ); } int main( ) { Box box1; cout<<box1.volume( )<<endl;
Box box2( 15 ); cout<<box2.volume( )<<endl; Box box3( 15,30 ); cout<<box3.volume( )<<endl; Box box4( 15,30,20 ); cout<<box4.volume( )<<endl;
system( “pause” ); return 0; }
5. 3 析构函数
析构函数非删除对象,而是完成一些内存清理工作。不能被重载,只能有一个。
※ 先构造的后析构,后构造的先析构。
5. 4 共用数据的保护
5. 4. 1 常对象
常对象所有成员的值都不能被修改。如果一个对象被定义成常对象,则不能调用该对象的非const 型的成员函数。
把数据成员声明为 mutable 可变数据成员,就可以用声明为 const 的成员函数来修改。
5. 4. 2 常对象成员
1) 常数据成员
只能通过构造函数的参数初始化表对常数据成员进行初始化。
2) 常成员函数
只能引用本类中的数据成员而不能修改它们。
5. 4. 3 指针
1) 指向对象的常指针
类型名 * const 指针变量名;
将指针变量声明为 const,这样指针始终保持为初值,不能改变。
Time t1( 10, 12 , 15 ) , t2 ;
Time *const ptr1 ;
ptrl = &t1 ;
ptrl = &t2 ; //错误,ptrl不能改变指向
2) 指向常对象的指针变量
const类型名 *指针变量名;
② 如果一个变量已被声明为常变量,只能用指向常变量的指针变量指向它。
② 指向常变量的指针变量除了可以指向常变量外,还可以指向被声明为 const 的变量。此时不能通过此指针变量改变该变量的值。
③ 如果函数的形参是指向 const 型变量的指针,允许实参是指向 const 变量的指针,或非 const 变量的指针。
5. 4. 4 对象的常引用
1) 引用
引用的作用是给变量起一个别名。变量名和引用名都指向同一段内存单元。
int a , c ;
int &b = a ; // b 是 a 的引用,& 是引用声名符,不代表地址。
int &b = c ; //错误
2) 如果形参为变量的引用名,实参为变量名,则在调用函数进行虚实结合时,把实参地址传给形参(引用名),这样引用名也指向实参变量。
5. 5 对象的动态建立与释放
※ new 和 delete 是运算符不是函数。
5. 6 静态成员(static)
5. 6. 1 静态数据成员
1) 如果只声明类而未定义对象,则类的一般数据成员不占用内存空间,只有定义对象时才为对象的数据成员分配空间。
静态数据成员在所有对象之外开辟空间,不定义对象,静态成员也要分配空间。
2) 静态数据成员不随对象的建立而分配空间,不随对象的释放而释放空间。
3) 静态数据成员只能在类体外进行初始化。
数据类型 类名::静态数据成员名 = 初值
4) 静态数据成员既可以通过对象名引用,又可以通过类名引用。
5) 静态数据成员的作用域仅限于定义该类的作用域内。
5. 6. 2 静态成员函数
和静态数据成员一样,静态成员函数是类的一部分,而不是对象的一部分。
静态成员函数没有 this 指针。
静态成员函数主要用来访问静态数据成员,而不访问非静态成员。
5. 7 友元(friend)
※ 友元的关系是单向的。
※ 友元的关系不能传递。
5. 7. 1 友元函数
友元函数可以访问这个类中的私有成员。
1) 将普通函数声明为友元函数
2) 友元成员函数,将另一个类中的成员函数声明为友元函数。
3) 一个函数可以被多个类声明为友元函数。
5. 7. 2 友元类
友元类的所有函数都是类的友元函数。
5. 8 类模板
※ 声明:template < class类型参数名 >
※ 定义:类模板名 < 实际类型名 > 对象名。
5. 9 重载(overloading)
5. 9. 1 函数重载
作用于不同类型的同一操作具有相同的名字。
5. 9. 2 运算符重载
运算符重载实际上是函数的重载。
一般格式:函数类型operator运算符名称(形参列表)
# include < iostream > using namespace std ; class Complex { public:
Complex ( ) { real = 0 ; image = 0 ;} Complex ( double r, double i ) { real = r ; image = i ;} Complex operator + ( Complex &c2 );
void display ( ) ;
private: double real; double image; }; Complex Complex::operator + ( Complex &c2 ) { Complex c ; c.real = real + c2.real ; c.image = image + c2.image ; return c; } void Complex::display ( ) { cout<<”(”<< real << “,”<< image <<”)”<<endl; } int main( ) { Complex c1 (3, 4 ) , c2 ( 5, -10 ) , c3; c3 = c1 + c2 ; c3.display ( ) ; system ( “pause” ) ; return 0 ; }
※ 运算符重载规则:
① C++ 不允许用户自己定义新的运算符,只能对已有的运算符进行重载。
② 不能重载的运算符: . , .* , :: , sizeof , ?:
③ 运算符重载的函数不能有默认的参数。
④
※ 双目运算符多重载为友元函数,多目运算符多重载为成员函数。重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象引用)。
※ 类型转换函数:operator类型名 ( ) { 实现转换的语句;}
不能有返回值,没有参数。
5. 10 继承与派生
5. 10. 1 派生类成员的访问属性
1) 公用继承(public inheritance)
基类的公用成员和保护成员在派生类中保持原有访问属性,私有成员仍为基类私有。
2) 私有继承(private inheritance)
基类的公用成员和保护成员在派生类中成了私有成员,私有成员仍为基类私有。
3) 受保护的继承(protected inheritance)
基类的公用成员和保护成员在派生类中成了保护成员,私有成员仍为基类私有。
5. 10. 2 派生类的构造函数和析构函数
派生类构造函数的一般形式:
派生类构造函数名(总参数列表):基类构造函数名(参数列表)
{ 派生类中新增数据成员初始化语句;}
Student1 ( int n, string name, char s, int a, string ad ):Student ( n, name , s )
{
age = a ;
addr = ad ;
}
或者
Student1 ( int n, string name, char s, int a, string ad ):Student ( n, name , s ),age ( a ), addr ( ad ) { }
5. 10. 3 多重继承
1) 概念
多重继承的声明:class D:public A, private B, protected C { };
派生类构造函数:
派生类构造函数名(总参数列表):基类1构造函数名(参数列表),基类2构造函数名(参数列表),基类3构造函数名(参数列表)
{ 派生类中新增数据成员初始化语句;}
2) 多重继承引起的二义性问题:在派生类对象后增加直接基类名,避免二义性
Class A { public: int a; void display(); }; Class B { public: int a; void display(); }; Class c:public A, public B { public: int b; void show(); }; C c; c.a = 3 ; //错误 c.display ( ) ; //错误 c.A::a = 3 ; //正确 c.B::display ( ) ; //正确
3) 虚基类
只保留一份基类成员,不会产生二义性。
① 声明:class派生类名:virtual 继承方式 基类名
② 初始化:在最后的派生类中不仅要负责对其直接基类进行初始化,还要负责对虚基类初始化
class A { A (int i){} …};
class B:virtual public A { B (int n ):A ( n ){}… };
class C:virtual public A { C (int n ):A ( n ){}… };
class D:public B,C { D ( int n ):A ( n ),B ( n ),C ( n ){}… };
5. 10. 4 基类与派生类的转换
1) 派生类可以向基类对象赋值。
2) 派生类可以代替基类对象向基类对象的引用进行赋值或初始化。
5. 11 多态性与虚函数
5. 11. 1 两类多态性
1) 静态多态性:函数重载和运算符重载。
2) 动态多态性:运行时多态,通过虚函数实现。
5. 11. 2 虚函数
1) 一个成员函数被声明为虚函数(virtual)后,其派生类中的同名成员都自动称为虚函数。
2) 虚析构函数
5. 11. 3纯虚函数与抽象类
1) 纯虚函数
一般形式:virtual函数类型 函数名(参数列表) = 0;
① 无函数体。② = 0不是返回值。③ 是一个声明语句,后面应该有分号。
2) 抽象类
不用来定义对象而只作为一种基本类型用作继承的类。
3)结论
① 一个基类包含一个或一个以上的纯虚函数,就是抽象基类。
② 抽象基类不能定义对象。
③ 抽象基类是本类族的公共接口。
④ 纯虚函数是在抽象基类中声明的,只有在抽象基类中才称为纯虚函数,在派生类中除非再次用 “= 0” 重新声明,否则就不是纯虚函数。
⑤ 区别静态关联与动态关联。
⑥ 在类的层次结构中,顶层或最上面几层可以是抽象基类。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异