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” 重新声明,否则就不是纯虚函数。

⑤ 区别静态关联与动态关联。

⑥ 在类的层次结构中,顶层或最上面几层可以是抽象基类。

posted @   码上领航者  阅读(11)  评论(0编辑  收藏  举报
编辑推荐:
· 从 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的设计差异
点击右上角即可分享
微信分享提示