友元关系可以继承_C++基础总结(四):C++ 类与对象初探——继承和重载

52d0f22e086f92bc24ac19b999ede69d.png

今天小编分享 C++ 类与对象——继承和重载 ,建议大家收藏慢慢学习,同时希望对大家的C++学习有所帮助。

da6a942c5ec02b441dc877bdcc707ce4.png

C++ 类 & 对象

C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++ 的核心特性,通常被称为用户定义的类型。

类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。

C++ 类定义

定义一个类,本质上是定义一个数据类型的蓝图。这实际上并没有定义任何数据,但它定义了类的名称意味着什么,也就是说,它定义了类的对象包括了什么,以及可以在这个对象上执行哪些操作。

类定义是以关键字 class 开头,后跟类的名称。类的主体是包含在一对花括号中。类定义后必须跟着一个分号或一个声明列表。例如,我们使用关键字 class 定义 Box 数据类型,如下所示:

classBox{public:
double length;// 盒子的长度
double breadth; // 盒子的宽度
double height; // 盒子的高度};

关键字 public 确定了类成员的访问属性。在类对象作用域内,公共成员在类的外部是可访问的。也可以指定类的成员为 private 或 protected。

定义 C++ 对象

类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型的变量一样。下面的语句声明了类 Box 的两个对象:

Box Box1;// 声明 Box1,类型为 Box Box Box2; // 声明 Box2,类型为 Box对象 Box1 和 Box2 都有它们各自的数据成员。

访问数据成员

类的对象的公共数据成员可以使用直接成员访问运算符 (.) 来访问。为了更好地理解这些概念,让我们尝试一下下面的实例:

实例

#include<iostream>using namespace std;
classBox{public:
double length;// 长度
double breadth; // 宽度
double height; // 高度}; int main( ){ Box Box1;
// 声明 Box1,类型为 Box Box Box2;
// 声明 Box2,类型为 Box double volume = 0.0;
// 用于存储体积
// box 1 详述
Box1.height = 5.0; Box1.length = 6.0; Box1.breadth = 7.0;
// box 2 详述
Box2.height = 10.0; Box2.length = 12.0; Box2.breadth = 13.0;
// box 1 的体积
volume = Box1.height * Box1.length * Box1.breadth;
cout << "Box1 的体积:" << volume <<endl;
// box 2 的体积
volume = Box2.height * Box2.length * Box2.breadth;
cout << "Box2 的体积:" << volume <<endl;
return 0;}

当上面的代码被编译和执行时,它会产生下列结果:

Box1 的体积:210Box2 的体积:1560

需要注意的是,私有的成员和受保护的成员不能使用直接成员访问运算符 (.) 来直接访问。

20815e02133ca9f94079fca42be204d3.png

C++ 继承

面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行时间的效果。

当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。

继承代表了 is a 关系。例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等。

基类 & 派生类

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

classderived-class:access-specifier base-class

其中,访问修饰符 access-specifier 是 public、protected 或 private 其中的一个,base-class 是之前定义过的某个类的名称。如果未使用访问修饰符 access-specifier,则默认为 private。

假设有一个基类Shape,Rectangle是它的派生类,如下所示:

实例

#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);
}}; int main(void){ Rectangle Rect;
Rect.setWidth(5);
Rect.setHeight(7);
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
return 0;}

当上面的代码被编译和执行时,它会产生下列结果:

Total area:35

740417c8817808924fe9d16dc5707da5.png

访问控制和继承

派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。

我们可以根据访问权限总结出不同的访问类型,如下所示:

343fc74a2abf0c6ddf59cd7fe94c75ba.png

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

基类的构造函数、析构函数和拷贝构造函数。

基类的重载运算符。

基类的友元函数。

继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用protected private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。

保护继承(protected):当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。

私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

多继承

多继承即一个子类可以有多个父类,它继承了多个父类的特性。

C++ 类可以从多个类继承成员,语法如下:

class<派生类名>:<继承方式1><基类名1>,<继承方式2><基类名2>,…{<派生类类体>};

其中,访问修饰符继承方式是 public、protected 或 private 其中的一个,用来修饰每个基类,各个基类之间用逗号分隔,如上所示。现在让我们一起看看下面的实例:

实例

#include<iostream>using namespace std;// 基类 Shapeclass Shape {
public:
void setWidth(int w){
width = w;
}
void setHeight(int h){
height = h;
}
protected:
int width;
int height;}; // 基类 PaintCostclass PaintCost {
public:
int getCost(int area){
return area * 70;
}}; // 派生类class Rectangle: public Shape, public PaintCost{
public:
int getArea(){
return (width * height);
}}; int main(void){
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeight(7);
area = Rect.getArea();
// 输出对象的面积
cout << "Total area: " << Rect.getArea() << endl;
// 输出总花费
cout << "Total paint cost: $" << Rect.getCost(area) << endl;
return 0;}

当上面的代码被编译和执行时,它会产生下列结果:

Total area:35Total paint cost:$2450

28c017ade7578d68ca509008b4d648da.png

C++ 重载运算符和重载函数

C++ 允许在同一作用域中的某个函数运算符指定多个定义,分别称为函数重载和运算符重载。

重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义(实现)不相同。

当您调用一个重载函数或重载运算符时,编译器通过把您所使用的参数类型与定义中的参数类型进行比较,决定选用最合适的定义。选择最合适的重载函数或重载运算符的过程,称为重载决策。

C++ 中的函数重载

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

下面的实例中,同名函数 print() 被用于输出不同的数据类型:

实例

#include<iostream>using namespace std;classprintData{
public:
voidprint(int i){
cout<<"整数为: "<<i<<endl;}voidprint(double f){
cout<<"浮点数为: "<<f<<endl;
}
voidprint(char c[]){
cout<<"字符串为: "<<c<<endl;
}};intmain(void){
printData pd;
// 输出整数
pd.print(5);
// 输出浮点数
pd.print(500.263);
// 输出字符串
char c[] = "Hello C++"; pd.print(c);
return 0;}

当上面的代码被编译和执行时,它会产生下列结果:

整数为:5浮点数为:500.263字符串为:Hello C++

cfc30a63ac09d4131d86275eca0c3c6a.png

C++ 中的运算符重载

您可以重定义或重载大部分 C++ 内置的运算符。这样,您就能使用自定义类型的运算符。

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

Box operator+(constBox&);

声明加法运算符用于把两个 Box 对象相加,返回最终的 Box 对象。大多数的重载运算符可被定义为普通的非成员函数或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那么我们需要为每次操作传递两个参数,如下所示:

Box operator+(constBox&,constBox&);

下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用 this 运算符进行访问,如下所示:

实例

#include<iostream>using namespace std;classBox{
public:
doublegetVolume(void){
returnlength*breadth*height;
}
voidsetLength(double len){
length=len;
}
voidsetBreadth(double bre){
breadth=bre;
}
voidsetHeight(double hei){
height=hei;
}
// 重载 + 运算符,用于把两个 Box 对象相加
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
private:
double length;
// 长度
double breadth;
// 宽度
double height;
// 高度};// 程序的主函数int main( ){
Box Box1;
// 声明 Box1,类型为 Box Box Box2;
// 声明 Box2,类型为 Box Box Box3;
// 声明 Box3,类型为 Box double volume = 0.0;
// 把体积存储在该变量中
// Box1 详述
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
// Box2 详述
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
// Box1 的体积
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume <<endl;
// Box2 的体积
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume <<endl;
// 把两个对象相加,得到 Box3 Box3 = Box1 + Box2;
// Box3 的体积
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume <<endl;
return 0;}

当上面的代码被编译和执行时,它会产生下列结果:

VolumeofBox1:210VolumeofBox2:1560VolumeofBox3:5400

好了,以上就是对 C++ 类与对象初探——继承和重载的分享。

如果你喜欢这篇文章的话,动动小指,加个关注哦~

0a8550bb103c0349e80ae12002768f13.png

如果你也想成为程序员,想要快速掌握编程,这里为你分享一个学习企鹅圈子!

里面有资深专业软件开发工程师,在线解答你的所有疑惑~C++入门“so easy”

编程学习书籍:

83c0b1ae8138b0b33e32d8334d3c29f0.png

编程学习视频:

50103ef84d8829ceae45ce0c26d6fd86.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中,如果要将一个函数声明为某个类的友元函数,则需要在该类的声明中进行声明。但是,如果该友元函数定义在类外部,那么在类外部也需要进行一次声明,以便编译器能够正确地解析该函数。这种声明通常是在类的定义之外进行的,类似于普通的函数声明。示例代码如下: ```cpp // 前置声明类 class MyClass; // 友元函数声明 void myFriendFunction(MyClass& obj); // MyClass 类的定义 class MyClass { public: // 构造函数 MyClass(int value) : m_value(value) {} // 友元函数声明 friend void myFriendFunction(MyClass& obj); private: int m_value; }; // 友元函数定义 void myFriendFunction(MyClass& obj) { // 可以访问 MyClass 的私有成员 std::cout << "The value of MyClass is: " << obj.m_value << std::endl; } int main() { MyClass obj(42); // 调用友元函数 myFriendFunction(obj); return 0; } ``` 如果要将一个类声明为另一个类的友元类,则需要在被声明的类的声明中进行声明。类似于友元函数,如果被声明的类定义在类外部,那么在类外部也需要进行一次声明。示例代码如下: ```cpp // 前置声明类 class MyClass2; // MyClass1 类的定义 class MyClass1 { public: // 构造函数 MyClass1(int value) : m_value(value) {} // 友元类声明 friend class MyClass2; private: int m_value; }; // MyClass2 类的定义 class MyClass2 { public: // 可以访问 MyClass1 的私有成员 void myFunction(MyClass1& obj) { std::cout << "The value of MyClass1 is: " << obj.m_value << std::endl; } }; int main() { MyClass1 obj1(42); MyClass2 obj2; // 调用 MyClass2 的成员函数 obj2.myFunction(obj1); return 0; } ``` 需要注意的是,友元函数和友元类的使用应该尽量避免。因为它们破坏了封装性,导致代码可维护性降低。只有在确实有必要访问私有成员时才应该使用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值