C++程序设计——类和对象的使用(this指针与const特性、友元函数和友元类、类的复合)

本篇博客是对课堂PPT、知识点的整理

目录

前言

一、类的复合

1.实例引入

(1)问题描述

(2) 面向对象设计

(3)说明

(4)实现代码

2.值得补充的一点细节 ‘ : ’

(1) const修饰的数据成员

(2) 类的复合 

二、this指针与const特性

1.this 指针

(1)this指针的作用

(2)在类的非静态方法中,可使用 this 指针

(3)实例说明 

2.const 特性

(1) 修饰对象

(2)修饰方法

(3)修饰数据成员

三、 友元函数和友元类

1.数据封装的“例外”

2.友元函数 

3.友元类 

(1)友元类声明方法 

(2)友元类的单向性 

(3)实例说明 

总结


前言

面向对象程序设计,一个很重要的点,就是数据的权限,或者说对内部数据的封装。本篇博客主要总结的就是相关对数据权限的操作或者设置,包括:this指针与const特性、友元函数和友元类。此外还对类的复合进行了说明和知识整理。


 

一、类的复合

  • 一个类的对象中,往往包含若干其他类的对象;或者说,一个类的对象往往是由许多其他类的对象组合而成的
  • 比如,一个汽车对象中一般包含四个车轮对象
     

1.实例引入

(1)问题描述

 定义一个圆类Circle,利用类的复合定义一个圆柱类Column,然后创建圆柱类Column的实例化对象

(2) 面向对象设计

 

(3)说明

  • 成员对象的构造函数会被自动调用
  • 如果成员对象的构造函数需要参数,参数也需要通过复合类的构造函数传递过去
  • 成员对象的析构函数会在复合类被撤销时自动调用

(4)实现代码

 Circle类

class Circle
{
private:
    double x, y, r;

public:
    Circle(double px, double py, double pr):    
         x(px), y(py), r(pr)
    {
        cout << "调用circle的构造函数" << endl;
    }

    ~Circle()
    {
        cout << "调用circle的析构函数" << endl;
    }
    
    double area()
    {
        return PI * r * r;
    }
};

Column类 

class Column
{
private:
    Circle circle;
    double height;

public:
    Column(double px, double py, double pr, double ph):
      circle(px, py, pr),
      height(ph)
    {
        cout << "调用column的构造函数" << endl;
    }

    ~Column()
    {
        cout << "调用column的析构函数" << endl;
    }

    double Volumn()
    {
        return circle.area() * height;
    }
};

2.值得补充的一点细节 ‘ : ’

值得注意的是,在上述例子,构造函数代码,初始化部分用了冒号 " : "来进行。

在程序中定义变量并初始化的机制中,有两种形式,一个是我们传统的初始化的形式,即
赋值运算符赋值,还有一种是括号赋值。

int a=10; 
char b='r';//赋值运算符赋值 

int a(10);
char b('r');//括号赋值 

但括号赋值只能在变量定义并初始化中,不能用在变量定义后再赋值,这是和赋值运算符赋值的不同之处

int a;  //先定义一个变量 
...... 
a=10;  //根据需要赋值

int b;   //先定义一个变量 
...... 
b(10);  //错误:编译器讲b当作函数名,尝试调用

冒号初始化与函数体初始化的区别在于:

冒号初始化是给数据成员分配内存空间时就进行初始化,就是说分配一个数据成员只要冒号后有此数据成员的赋值表达式(此表达式必须是括号赋值表达式),那么分配了内存空间后在进入函数体之前给数据成员赋值,就是说初始化这个数据成员此时函数体还未执行。对于在函数中初始化,是在所有的数据成员被分配内存空间后才进行的。

因此大致有两种情况必须用" : "进行初始化: 

(1) const修饰的数据成员

const修饰常量,即const修饰的对象只能在初始化的时候赋值,因此在分配空间时就进行初始化 。

(2) 类的复合 

当子类的构造需要参数时,也需要在分配空间时就进行初始化,因此也需要用" : "进行初始化。


二、this指针与const特性

1.this 指针

  • 在每个非静态函数中都能访问一个名为 this 的指针,这个指针恰好指向当前对象
  • this 指针的类型与当前类相关:Circle 对象 this 指针的类型为 Circle*, Column 对象 this 指针的类型为 Column*
  • 注意, this 指针是常量,不能被重新赋值

(1)this指针的作用

  • 定位当前对象:
    return * this ;
    
  • 定位当前对象成员:
    void * Student::setNumber(int  number) {
        this-> number = number; }
    

(2)在类的非静态方法中,可使用 this 指针

Stack :: ~Stack() {
     this->size = 0;
     this->top=0;
     objNum--;
    delete[] this->data;
}
void Student :: setName(char* name) {
     strcpy( this->name, name);
}

(3)实例说明 

 定义一个类,要求其对象可以连续调用其成员函数,创建该类的对象并连续调用其成员函数

 

class Test
{
private:
    int data;

public:
    Test() {
        data = 0;
    }

    ~Test(){}

    Test& setData(int n) {
        data = n;
        return *this;
    }

    void print() {
        cout << "data = " << data << endl;
    }
};

int main() {
    Test t;
    t.setData(5).print();
    return 0;
}

2.const 特性

  • 用 const修饰变量:const int x = 5;
  • 用 const 限制函数参数: int sum(const int data[])
  • 用 const 修饰指针
  • const指针:int* const p = &x;  p = &y; (X)
  • 指向常量的指针:const int*p = &x; *p = 5; (X)
  • 指向常量的const指针:const int* const p = &x;

在面向对象部分,const 关键字有几个额外作用

  1. 修饰对象
  2. 修饰方法
  3. 修饰数据成员 

(1) 修饰对象

const 对象

  • 当希望某个对象的数据成员不被修改时,可以将其声明为 const 对象,例如: const Circle;

const 对象的使用规则

  • const 对象不能调用非 const 方法;
  • const 对象成员的赋值只能在构造方法中进行
  • 例:
    const Complex  c (3,5);
    const Complex * pcs = new Complex(1,2);
    c. setReal(2);         //错误
    pst -> setImage(5);    //错误
    

(2)修饰方法

const方法 

  • 如果希望类的某方法不修改当前对象的数据成员,则可以将该方法声明为 const 方法
  • const 关键字应放在函数头部的后面,如
    int Complex::getReal() const {
         return this->real;}
    

const方法使用限制

  • 不能修改当前对象的数据成员的值 

(3)修饰数据成员

const 数据成员

  • 如果希望某些数据成员在对象产生后不发生修改,则可以将其声明为 const 成员
  • 声明 const 数据成员时,应将 const 置于数据成员前。比如:对于 Stack 类,可以将 size 成员作为 const 数据成员,其书写方式为 const int size; 

const数据成员的使用限制

  • const 数据成员不允许修改
  • const 数据成员只能在构造方法中初始化,但不能以赋值方式进行 

三、 友元函数和友元类

1.数据封装的“例外”

  1.  一般情况下,数据成员的访问权限为私有,其值只允许被本类的方法访问;
  2. 但某些情况下,希望其数据成员能够被个别的外部方法访问。

2.友元函数 

  1.  一个类的友元函数是该类的外部函数,但它有权限访问类的所有成员,包括私有成员和受保护成员
  2. 友元函数可以是某个全局函数(不属于任何类的函数),也可以是某个类的成员函数
class Triangle 
{
    friend void setA(Triangle &, int);
public: 
    Triangle(int x=5, int y=5, int z=5):
        a(x), b(y), c(z)
    { }

    void print() {
        cout << a << " " << b << " " << c << endl;
    }
private:
    int a, b, c;
};

void setA(Triangle & t, int a){
    t.a = a;
}

int main() {
    Triangle t;
    setA(t, 10);
    t.print();
    return 0;
}

3.友元类 

一个类可以把另外一个类声明为其友元类。其友元类的所有成员函数都可以访问该类的全部成员,包括私有成员和受保护成员

(1)友元类声明方法 

  • 在类定义中,在要声明的友元类的前面加上 friend 关键字

(2)友元类的单向性 

  • A 为 B 的友元,并不意味着 B 也是 A 的友元
  • A为 B 的友元,B 为 C 的友元,并不说明 A是 C 的友元

以数学化(离散数学)的角度来说,友元这种关系不是传递的也不是对称的。

以形式化的方式说,你把真心给那个她,她却未必把真心给你。 

(3)实例说明 

class B;
class A {
public: 
     void setB(B&, int);
     void print(B &);
};

class B {
     friend class A; 
private:
     int data;
};

void A::print(B& b) {
    cout <<“The data of object B:”<<b.data<<endl;
};


总结

本篇内容,对类的复合、this指针与const特性、友元函数和友元类的相关知识进行了汇总。

这些C++的特性,都是围绕一个核心理念:类成员信息的封装以及特殊权限控制。正式因为这些控制方式,才使得在项目实战中,规避了许多难题,也简化了很多实现问题。

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值