c++面向对象

二、c++面向对象知识

2.1 c++类和对象

1. c++类的成员函数

类成员函数是类的一个成员,它可以操作类的任意对象,可以访问对象中的所有成员。

定义成员函数
  • 成员函数可以定义在类定义内部;
  • 使用范围解析运算符 :: 来定义。
// (1)类内定义
class Box
{
   public:
      double length;      // 长度
      double breadth;     // 宽度
      double height;      // 高度
   
      double getVolume(void)
      {
         return length * breadth * height;
      }
};

// (2)类外定义,成员函数类内声明
double Box::getVolume(void)
{
    return length * breadth * height;
}

2. c++类访问修饰符

(1) public

公有成员在程序中类的外部是可访问的。

(2) private

私有成员变量或函数在类的外部是不可访问的,甚至是不可查看的。只有类和友元函数可以访问私有成员。
默认情况下,类的所有成员都是私有的。

#include <iostream>
 
using namespace std;
 
class Box
{
   public:
      double length;
      void setWidth( double wid );
      double getWidth( void );
 
   private:
      double width;
};
 
// 成员函数定义
double Box::getWidth(void)
{
    return width ;
}
 
void Box::setWidth( double wid )
{
    width = wid;
}
 
// 程序的主函数
int main( )
{
   Box box;
 
   // 不使用成员函数设置长度
   box.length = 10.0; // OK: 因为 length 是公有的
   cout << "Length of box : " << box.length <<endl;
 
   // 不使用成员函数设置宽度
   // box.width = 10.0; // Error: 因为 width 是私有的
   box.setWidth(10.0);  // 使用成员函数设置宽度
   cout << "Width of box : " << box.getWidth() <<endl;
 
   return 0;
}
(3) protected

protected成员变量或函数与私有成员十分相似,但protected成员在派生类(即子类)中是可访问的。
(子类可以访问protected)

#include <iostream>
using namespace std;
 
class Box
{
   protected:
      double width;
};
 
class SmallBox:Box // SmallBox 是派生类
{
   public:
      void setSmallWidth( double wid );
      double getSmallWidth( void );
};
 
// 子类的成员函数
double SmallBox::getSmallWidth(void)
{
    return width ;
}
 
void SmallBox::setSmallWidth( double wid )
{
    width = wid;
}
 
// 程序的主函数
int main( )
{
   SmallBox box;
 
   // 使用子类对象调用子类成员函数设置宽度
   box.setSmallWidth(5.0);
   cout << "Width of box : "<< box.getSmallWidth() << endl;
 
   return 0;
}
(4)继承中的特点
  • public 继承:基类成员的访问属性在派生类中保持不变
  • protected 继承:基类 public 成员,protected 成员,private 成员的访问属性在派生类中分别变成:protected, protected, private
  • private 继承:基类 public ,protected,private 的访问属性在派生类中分别变成:private, private, private。
继承方式基类的public成员基类的protected成员基类的private成员继承引起的访问控制关系变化概括
public继承仍为public成员仍为protected成员不可见基类的非私有成员在子类的访问属性不变
protected继承变为protected成员变为protected成员不可见基类的非私有成员都为子类的保护成员
private继承变为private成员变为private成员不可见基类中的非私有成员都称为子类的私有成员

2.2 c++ 继承

1. 访问控制和继承

一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类。类派生列表以一个或多个基类命名。

#include <iostream>
using namespace std;
 
// 基类
class Shape 
{
   public:
      void setWidth(int w)
      {
         width = w;
      }
      void setHeight(int h)
      {
         height = h;
      }
   protected:
      int width;
      int height;
};
 
// 派生类
class Rectangle: public Shape
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
      void setW2(int w)
      {
         width = w * 2;   // 派生类可以访问基类的保护对象
      }
};
 
int main(void)
{
   Rectangle Rect;
 
   Rect.setWidth(5);  // 派生类调用基类函数
   Rect.setHeight(7);
 
   // 输出对象的面积
   cout << "Total area: " << Rect.getArea() << endl;

   Rect.setW2(7);
   cout << "Total area: " << Rect.getArea() << endl;
 
   return 0;
}

一个派生类继承了所有的基类方法,但下列情况除外

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。

2. 多继承

C++ 类可以从多个类继承成员:

// 派生类
class Rectangle: public Shape, public PaintCost
{
   public:
      int getArea()
      { 
         return (width * height); 
      }
};

2.3 c++ 重载

c++ 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载
当调用一个重载函数或重载运算符时,编译器通过将使用的参数类型与定义中的参数类型进行比较。

1. C++ 中的函数重载

在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数。

#include <iostream>
using namespace std;

class printData
{
   public:
      void print(int i) {
        cout << "整数为: " << i << endl;
      }
 
      void print(double  f) {
        cout << "浮点数为: " << f << endl;
      }
 
      void print(char c[]) {
        cout << "字符串为: " << c << endl;
      }
};

int main(void)
{
   printData pd;

   // 输出整数
   pd.print(5);
   // 输出浮点数
   pd.print(500.263);
   // 输出字符串
   char c[] = "Hello C++";
   pd.print(c);
   return 0;
}

2. C++ 中的运算符重载

重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表。

// 定义为成员函数(类内)
Box operator+(const Box&);

// 定义为非成员函数(类外)
Box operator+(const Box&, const Box&);
  • 类的成员函数,每次操作需要传递两个参数
  • 类的成员函数中,对象作为参数进行传递,对象的属性使用 this 运算符访问
#include <iostream>
using namespace std;
 
class Box
{
   public:
 
      double getArea(void)
      {
         return length * breadth;
      }
      void setLength( double len )
      {
          length = len;
      }
 
      void setBreadth( double bre )
      {
          breadth = bre;
      }
 

      // 重载 + 运算符,用于把两个 Box 对象相加
      Box operator+(const Box& b)
      {
         Box box;
         box.length = this->length + b.length;
         box.breadth = this->breadth + b.breadth;
         return box;
      }
   private:
      double length;      // 长度
      double breadth;     // 宽度
};
// 程序的主函数
int main( )
{
   Box Box1;                // 声明 Box1,类型为 Box
   Box Box2;                // 声明 Box2,类型为 Box
   Box Box3;                // 声明 Box3,类型为 Box
   double area = 0.0;     // 把体积存储在该变量中
 
   // Box1 详述
   Box1.setLength(6.0);
   Box1.setBreadth(6.0); 
 

 
   // Box2 详述
   Box2.setLength(10.0); 
   Box2.setBreadth(11.0); 

 
   // Box1 的体积
   area = Box1.getArea();
   cout << "Area of Box1 : " << area <<endl;
 
   // Box2 的体积
   area = Box2.getArea();
   cout << "Area of Box2 : " << area <<endl;
 
   // 把两个对象相加,得到 Box3
   Box3 = Box1 + Box2;
 
   // Box3 的体积
   area = Box3.getArea();
   cout << "Area of Box3 : " << area <<endl;
 
   return 0;
}
  • 运算符重载也可以发生函数重载
// 类的非成员函数无法访问private,需要设置为public或者通过成员函数访问
//通过全局函数运算符重载
Box operator+ (const Box& b1, const Box& b2)
{
    Box temp;
    temp.length = b1.length + b2.length;
    temp.breadth= b1.breadth + b2.breadth;
    return temp;
}

//运算符重载也可以发生函数重载
Box operator+ (const Box& b1, const int num)
{
    Box temp;
    temp.length = b1.length + num;
    temp.breadth = b1.breadth+ num;
    return temp;
}
可重载运算符/不可重载运算符

(1) 可重载的运算符

运算符具体
双目算术运算符+ ,-,*,/,% (取模)
关系运算符==,!= ,< ,> ,<=,>=
逻辑运算符||,&& ,!
单目运算符+ (正),-(负),*(指针),&(取地址)
自增自减运算符++,–
位运算符| ,& ,~,^,,<< ,>>
赋值运算符=, +=, -=, *=, /= , % = , &=, |=, ^=, <<=, >>=
空间申请与释放new, delete, new[ ] , delete[]
其他运算符()(函数调用),->(成员访问),,(逗号),[](下标)

(2) 不可重载的运算符

运算符解释
.成员访问运算符
., ->成员指针访问运算符
::域运算符
sizeof长度运算符
?:条件运算符
#预处理符号

2.4 c++多态

当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。

C++ 多态意味着调用成员函数时,会根据调用函数对象的类型来执行不同的函数。核心理念就是通过基类访问派生类定义的函数。

1. 多态的分类

  • 静态多态:函数重载,泛型编程
  • 动态多态:虚函数(重写)

2. 静态多态

编译器在编译期间完成的,编译器根据函数实参的类型(可能会进行隐式类型转换),可推断出要调用那个函数,如果有对应的函数就调用该函数,否则出现编译错误。

静态多态有两种实现方式:

  • 函数重载:包括普通函数的重载和成员函数的重载
  • 函数模板的使用(泛型编程)
// print()函数
void print(const char* str,int width);
void print(double i ,int width);
void print(const char* str);
// 使用print()函数时,编译器将根据所采取的用法使用有相应特征标的原型
print("abc",12);
print(2.2,55);
print("def");

3. 动态多态

虚函数

虚函数是在基类中使用关键字 virtual声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。
在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。

纯虚函数

基类中不能对虚函数给出有意义的实现,但是希望在派生类中给出定义以便更好的适用对象。这个时候就会用到纯虚函数。

// 纯虚函数定义
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      // pure virtual function
      virtual int area() = 0;
};
多态的实现
#include <iostream> 
using namespace std;
 
class Shape {
   protected:
      int width, height;
   public:
      Shape( int a=0, int b=0)
      {
         width = a;
         height = b;
      }
      // 不加virtual是静态链接 
       virtual int area()
      {
         cout << "Parent class area :" <<endl;
         return 0;
      }
};
class Rectangle: public Shape{
   public:
      Rectangle( int a=0, int b=0):Shape(a, b) { }
      // 多态
      int area ()
      { 
         cout << "Rectangle class area :" <<endl;
         return (width * height); 
      }
};
class Triangle: public Shape{
   public:
      Triangle( int a=0, int b=0):Shape(a, b) { }
      // 多态
      int area ()
      { 
         cout << "Triangle class area :" <<endl;
         return (width * height / 2); 
      }
};
// 程序的主函数
int main( )
{
   Shape *shape;
   Rectangle rec(10,7);
   Triangle  tri(10,5);
 
   // 存储矩形的地址
   shape = &rec;
   // 调用矩形的求面积函数area
   shape->area();
 
   // 存储三角形的地址
   shape = &tri;
   // 调用三角形的求面积函数area
   shape->area();

   /*非多态
    rec.area();
    tri.area();
   */
   
   return 0;
}
形成多态的三个必备条件
  • 存在继承关系
  • 继承关系有同名虚函数
  • 存在基类的指针或引用,通过该指针和引用调用虚函数

4. c++ 接口(抽象类)

  • C++ 接口是使用抽象类来实现的,如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 “= 0” 来指定的.

  • 设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会导致编译错误。

  • 如果一个 ABC 的子类需要被实例化,则必须实现每个纯虚函数。如果没有在派生类中重写纯虚函数,就尝试实例化该类的对象,会导致编译错误。

class Box
{
   public:
      // 纯虚函数
      virtual double getVolume() = 0;
   private:
      double length;      // 长度
      double breadth;     // 宽度
      double height;      // 高度
};

5. 重载和重写区别

  • 范围区别:重写和被重写的函数在不同的类中,重载和被重载的函数在同一类(作用域)中。

  • 参数区别:重写与被重写的函数参数列表一定相同,重载和被重载的函数参数列表一定不同。

  • virtual的区别:重写的基类函数必须要有virtual修饰,重载函数和被重载函数可以被virtual修饰,也可以没有

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值