C++继承基础详解

访问控制和继承
派生类可以访问基类中的所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应该在基类中声明
为private
我们可以根据访问权限总结出不同的访问类型

访问publicprotectprivate同一个类yesyesyes派生类yesyesno外部类yesnono

一个派生类继承了所有的基类方法,但下列情况除外:
基类的构造函数、析构函数、拷贝构造函数
基类的重载运算符
基类的友元函数

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

我们几乎不用protected或private继承,通常使用public继承。
当使用不同类型的继承时,遵循以下几个原则:
公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protect):当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

多继承
多继承即一个子类可以有多个父亲,它继承了多个父亲的特性。
C++类可以从多个类继承成员,语法如下
class :,,...
{

};
其中,访问修饰符继承方法是public,protected或private其中的一个,用来修饰每个基类,各个基类之间用逗号分隔,
如上图所示。现在我们看看下面的实例
#include
using namespace std;
//基类 Shape
class Shape
{
public:
void setWidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
protected:
int width;
int height;
};
//基类PaintCost
class 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;

}
我们来分析一下上面的代码。
它首先创建了一个基类Shape. Shape类中包含两个保护成员变量,保护成员变量在派生类进行public公有继承的时候是可以被继承的。
因此在后面main()方法中派生类Rect在调用自己的方法getArea时可以在基类Shape中找到width和height。
Rect当然可以使用基类Shape的两个公有成员方法。这两个公有成员方法的作用是给两个成员变量赋值,它让width等于参数w的值
void setwidth(int w)
{
width = w;
}
void setHeight(int h)
{
height = h;
}
//在下面的main()方法中调用这两个方法
Rect.setWidth(5); //将width设为5
Rect:setHeight(7); //将height设为7
area = Rect.getArea();//getArea是Rect自己的public方法,虽然这个getArea方法里面用到的是Shape基类中的两个protect成员变量
//但好在公有继承可以访问基类中的protect
最后先使用Rect自带的getArea方法(Rect是Rectangle类的一个实例化,也就是说Rect所带的属性跟Rectangle一模一样,Rectangle可以使用什么方法,它也可以,Rectangle有什么成员变量它也有
相当于是Rectangle的一个分身,只不过名字不一样,实例化的过程很简单,就是main()里面的第一句Rectangle Rect;)最后将使用从基类PaintCost那里
公有继承过来的public 方法getCost,最后输出它
我们现在重新写一遍
#include
using namespace std;
class Shape
{
public:
void setWidth(int w)
{
width = w
}
void setHeight(int h)
{
height = h
}
protect:
int width;
int height;
};
//在定义类的时候要注意先写类方法的属性
//比如说
public:
void setWidth(int w)
{
width = w;
}
//而且类方法中的最后一个大括号不要加;但是类需要,上上面的代码块中将width和height也用protect赋了属性
//这样方法外部类就访问不到了,但派生类却可以。
//我们继续写一下所建立的基类PaintCost
class PaintCost
{
public:
int getCost(int area)
{
return area * 70;
}
};
//我们从这个基类中可以看出它要求一个参数,代表面积,getCost方法用来计算价格。
//接下来我们写最有意思的派生类,还记得派生类如何继承吗?
class Rectangle: public Shape, public PaintCost
//是的直接在类名后面加: 然后填上继承方式和继承对象就好啦。
//回顾一下不同的继承方式会有什么样的继承效果?
公有继承后属性不变,保护继承后,基类的公有和保护成为派生类的保护成员
私有继承后,基类的公有和保护将成为派生类的私有成员,那基类的私有成员到哪去了呢?
要记住派生类无法直接继承和访问基类中的私有成员,因此被称为私有成员,但是友元却可以,很神奇吧
过一会我们来学习友元。
//我们接着往下写派生类
class Rectangle:public Shape, public PaintCost
{
public:
int getArea()
{
return (width * height)
}
};
//那么我们还有一个main()方法必不可少
int main(void)
{
//首先先实例化派生类
Rectangle Rect;
int area;
Rect.setWidth(5);
Rect.setHeigh(7);
area = Rect.getArea();

cout << "Total area: " << Rect.getArea() << endl;
cout << "Total paint cost: $" <<Rect.getCost(area) <<endl;
return 0;

}
从整体上来看这道题目设计十分优秀,它创建的两个基类,一个用于赋值,一个计算cost,而最终都得要与面积area相关联
而派生类恰恰求面积,因此这道题的三个类的联系十分密切,通俗易懂,非常有趣。

重载运算符和重载函数
C++运行函数和运算符有多个定义,分别称为函数重载和运算符重载。
重载声明是指一个与之前已经在该作用域中声明过的函数或方法具有相同名称的声明,但是它们的参数参数列表和定义并不相同。

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

C++中的函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(参数个数,参数类型,顺序)
必须不同(函数的参数列表也称特征标)。不能仅通过返回类型来重载函数。
#include
using namespace std;
class printData
{
public:
void print(int i){
cout << "整数为: " << i << endl;
}
void print(double f){
cout << "浮点数为:" << i << endl;
}
void print(char c[]) {
cout << "字符串为:" << c << endl;
}
};
int main()
{
printData pd;

pd.print(5);
pd.print(500.263);
char c[] = "Hello C++";
pd.print(c);
return 0;

}
//第三个重载print结收的参数类型为数组
void print(char c[]){
cout << "字符串为:" << c << endl;
}
//要注意使用类之前要先进行实例化。
//我们来重写一下这个类
#include
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;

}
要注意形参变量叫啥都行,特征标不管变量名称,它只在乎变量的类型和顺序。
而且在使用数组形参之前要定义出这个数组
char c[] = "Hello C++";
pd.print(c);
C++中的运算符重载
实际上我们可以重载大部分C++中的运算符,这样,我们就能使用自定义类型的运算符。

重载的运算符是带有特殊名称的函数,函数名是由关键字operator和其后要重载的运算符符号构成的。
与其他函数一样,重载运算符有一个返回类型和一个参数列表。
Box operator+(const Box&);
声明加法运算符用于把两个Box对象相加,返回最终的Box对象。大多数的重载运算符可被定义为普通的非成员函数
或者被定义为类成员函数。如果我们定义上面的函数为类的非成员函数,那我们需要为每次操作传递两个参数,
如下所示:
Box operator+(const Box&, const Box&);
如果是类成员函数则已经在类中,也就是说已经知道一个类了,只有将另一个类作为参数就可以了
因此只有const Box&,需要注意的是Box&代表的是Box对象的意思。

下面的实例使用成员函数演示了运算符重载的概念。在这里,对象作为参数进行传递,对象的属性使用this运算符进行访问
如下所示:
#include
using namespace std;
class Box
{
public:
double getVolume(void)
{
return length * breadth * height;
}
void setLength(double len)
{
length = len;
}
void setBreadth(double bre)
{
breadth = bre;
}
void setHeight(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;
Box Box2;
Box Box3;
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);
volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume << endl;
//把两个对象相加,得到Box3
Box3 = Box1 + Box2;
volume = Box3.getVolume();
cout << "Volume of Box3: " << volume << endl;
return 0;

}
该代码块首先先将Box作为一个类,类中有成员方法,有运算符重载,还有成员。
它将成员设为私有因此一般我们无法直接访问得到,但是通过该类中的成员函数可以访问到,因为在类中,所有成员信息都是共享的,这
就意味着该函数自带的类成员方法可以访问到这些private值。而刚好我们所需要的也就是它们的乘积。
接下来,我们重点分析一下这个成员运算符重载
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;
}
这个类成员加法运算符重载很有意思。
Box operator+(const Box& b)//这句话是标准运算符重载格式
//意思是我现在要接收一个叫b的Box对象,当然这个b只是个中间名。然后返回一个Box对象。
//我们接下来看看加法运算符重载的具体实现
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
box.height = this->height + b.height;
return box;
}
//它先实例化出来一个名为box的Box类。但是这个新实例化出来的类哪有什么值呢?
//所以我们得给它赋值,那我们想到了可以将原来的值和另一个对象的值相加,最后得出的结果赋给这个box
//这就很好的解决了两个对象相加的问题,也就是加法运算符重载。
//最后我们将实例化出的这个Box类返回给一个名为Box3的Box类,(实际上返回的这个类也是个类,将它赋值给Box3
也是因为赋值为变量好操作,实际上这个返回值的本质还是一个和对象)
好,我们将上面的代码重新写一遍
重新进行梳理
#include
using namespace std;
class Box
{
public:
double getVolume(void)
{
return lengthbreadthheight;
}
void setLength(double len)
{
length = len;
}
void setBreadth(double bre)
{
breadth = bre;
}
void setHeight(double hei)
{
height = hei;
}
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 height;
double breadth;
};
//程序的主函数
int main()
{
Box Box1;
Box Box2;
Box Box3;
double volume = 0;
//它上面实例化出来三个是Box类的,并将体积设置为0,
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
//该过程将Box1,Box2中的私有成员变量都赋上对应的值,因为成员变量是私有的因此无法直接访问,就利用类中成员函数可以访问成员变量的特点
利用getVolume函数将体积计算出来
volume = Box1.getVolume();
cout << "Volume of Box1: " << volume << endl;
volume = Box2.getVolume();
cout << "Volume of Box2: " << volume << endl;
Box3 = Box1 + Box2;
//在我们定义的加法重载中只能进行对象的相加
volume = Box3.getVolume();
//上面为volume定义的伏笔在这出来了。
cout << "Volume of Box3 :" << volume << endl;
return 0;

}
好,为了巩固一下我们将这段代码重新复习一遍
#include
using namespace std;
class Box//class Box后面没有
{
public:
double getVolume(void)
{
return lengthbreadthheight;
}
void setLength(double len)
{
length = len;
}
void setBreadth(double bre)
{
breadth = bre;
}
void setHeight(double hei)
{
height = hei;
}
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;
}
private:
double length;
double breadth;
double height;
};
int main()
{
Box Box1;
Box Box2;
Box Box3;
double volume = 0.0;
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);

volume = Box1.getVolume();
cout << "Volume of Box1 : " << volume << endl;
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume << endl;
Box3 = Box1 + Box2;
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume << endl;
return 0;

}

include

using namespace std;
class Box
{
public:
double getVolume(void)
{
return lengthbreadthheight;
}
void setLength(double len)
{
length = len;
}
//像这样设置成员变量的成员函数都是没有返回值的,他们直接改变成员变量
//这样下次有输出成员变量的时候就会发现它已经被替换
void setBreadth(double bre)
{
breadth = bre;
}
void setHeight(double hei)
{
height = hei;
}
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;
}
//运算符重载在public中
private:
double length;
double height;
double breadth;

};
int main()
{
Box Box1;
Box Box2;
Box Box3;
double volume = 0.0;

Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);
Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
volume = Box1.getVolume();
cout << "Volume of Box1 :" << volume << endl;
volume = Box2.getVolume();
cout << "Volume of Box2 :" << volume << endl;
Box3 = Box1 + Box2;
volume = Box3.getVolume();
cout << "Volume of Box3 : " << volume << endl;
return 0;

}
这段代码由三步构成:
创建Box类,类中要包含自己的成语变量,和成员函数和运算符重载
注:要知道类中的成员变量一般设为private属性,成员函数和运算符重载设置为public属性
在main()函数中对类进行实例化和初始化。
按要求将两个对象进行相加并输出
#include
using namespace std;
class Box
{
public:
double getVolume(void)
return lengthbreadthheight;
void setLength(double len)
{
length = len;
}
void setBreadth(double bre)
{
breadth = bre;
}
void setHeight(double hei)
{
height = hei;
}
Box operator+(const Box& b)
{
Box box;
box.length = this->length + b.length;
box.breadth = this->breadth + b.breadth;
boc.height = this->height + b.height;
return box;
}
};
int main()
{
Box Box1;
Box Box2;
Box Box3;
double volume;
Box1.setLength(6.0);
Box1.setBreadth(7.0);
Box1.setHeight(5.0);

Box2.setLength(12.0);
Box2.setBreadth(13.0);
Box2.setHeight(10.0);
volume = Box1.getVolume();
cout << "Volume of Box1 :" << volume << endl;
volume = Box2.getVolume();
cout << "Volume of Box2 : " << volume << endl;
Box3 = Box1 + Box2;
volume = Box3.getVolume();
cout << "Volume of Box3 :" << volume << endl;
return 0;

}

全部评论

相关推荐

昨天 18:53
海南大学 Java
华为 Java开发 25K*16
点赞 评论 收藏
分享
如题如果提出了一个薪资,A不成功,会有可能被取消offer吗
爱打瞌睡的柯基:最想去你们公司 但是别家开的高一些,希望能申请高一点 不管结果如何都谢谢你
点赞 评论 收藏
分享
11-15 18:39
已编辑
西安交通大学 Java
全村最靓的仔仔:卧槽,佬啥bg呢,本也是西交么
点赞 评论 收藏
分享
评论
点赞
收藏
分享
牛客网
牛客企业服务