this指针
不进行详细解释 一般情况下用不着
#include <iostream>
using namespace std;
class Human
{
char james;
Human(char james);//构造函数 传入参数
};
Human::Human(char james)//对构造函数进行初始化
{
james = james;
//在fishc=fishc之前 所有的语法没有任何问题 虽然Human构造器中有一个名为james的参数
//虽然他与Human类中的属性同名 但却是不相干的两样东西 所以并没有错误
//如何向构造器知道哪个是参数 哪个是属性 就需要用到 this指针 (指向当前类生成的对象)
this->james = james;
//添加this指针后 编译器就知道 赋值操作符左边将被解释为当前对象的James属性 右边将被解释为构造器传入来的james参数
//todo如果代码不存在二义性隐患,不必使用this指针!
}
类的继承
什么是类
类是提供封装的逻辑单位,类的每一个对象都包含有描述其自身状态的数据集合,并且通过接收特定的消息来处理这个数据集合。如果程序设计人员能够通过增加、修改或替换指定类的部分内容的方法对该类进行剪裁,就可以适应不同的应用,从而在很大程度上增强了数据封装的价值
什么是类的继承
继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易
当一个类被其他的类继承时,被继承的类称为基类, 继承其他类属性的类称为派生类,又称为子类 每个子类均将继承在它的基类里定义的方法和属性
当创建一个类时( 派生类(子类)),您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可( 基类(父类)) 这个已有的类称为基类,新建的类称为派生类
继承 代表了子类与基类关系, 例如,哺乳动物是动物,狗是哺乳动物,因此,狗是动物,等等
基类 & 派生类
一般情况下,继承的进程起源于一个基类的定义,基类定义了其所有派生类的公有属性,基类具有同一类集合中的公共属性,派生类继承了这些属性,并且增加了自己特有的属性。从任何已存在的类继承的实质就是建造新的派生类
一个类可以派生自多个类,这意味着,它可以从多个基类继承数据和函数。定义一个派生类,我们使用一个类派生列表来指定基类, 类派生列表以一个或多个基类命名,形式如下:
class 派生类名: 访问控制关键字 基类名 ( SubClass为子类名 BaseClass为基类名)
class SubClass:public BaseClass
{
数据成员和成员函数声明
};
其中,访问控制关键字 public 是 public、protected 或 private 其中的一个,BaseClass
是之前定义过的某个类的名称(基类),如果未使用访问控制关键字,则默认为private
(私有性访问)
如果基类中定义了一个静态成员,则在整个继承体系中只存在该成员的唯一定义。不论从基类中派生出多少个类,对于每个静态成员来说都只存在唯一的实例对于静态成员的访问控制规则,则是和其他的成员一样,如果基类中静态成员是private的,则派生类无权访问,如果静态成员是可以访问的,则我们既能通过基类使用它们,也可以通过派生类使用它 (但是在类内部可以的)
单重继承、多重继承与继承链
单继承
从一个基类派生的继承称为单继承,换句话说, 派生类只有一个直接基类,单继承声明语句的常用格式为:
class 派生类名: 访问控制关键字 基类名
{
数据成员和成员函数声明
};
例如:
class monkey :public Animal
{
public:
void climb();
};
多继承
从多个基类派生的继承称为多继承或多重继承,也就是说, 一个派生类有多个直接基类。在某些面向对象的语言(如Java)中不支持类间的多重继承而只支持单重继承,即一个类至多只能有一个直接父类,因此实现类似的功能需要借助接口等其他机制。而在C++中提供了多重继承的语法支持,使得问题变得简单了许多。多重继承声明语句的常用格式为:
class 派生类名: 访问控制关键字 基类名1, 访问控制关键字 基类名2,...
{
数据成员和成员函数声明
};
例如:
class monkey :public Animal , public looklike
{
public:
void climb();
};
继承链
除了多重继承之外,一个派生类继承多个基类还有一种方法,就是把派生类作为基类再次供别的类继承,产生多层次的继承关系。例如类A派生类B,类B派生类C,则称类A是类B的直接基类,类B是类C的直接基类,类A是类C的间接基类。类的层次结构也叫做继承链。还是上面的例子,当建立类C的对象时,类A的构造函数最先被调用,接下来被调用的是类B的构造函数,最后是类C的构造函数。析构函数的调用顺序正好相反。当一个派生类继承有层次的类时,继承链上的每个派生类必须将它需要的变量传递给它的基类
例如:
class Base {..............};
class D1 : public Base {..............};
class D2 : public D1 {........................};
由于每个类都是继承其直接基类的所有成员,所以对于一个最终的派生类来说,它会继承其直接基类的成员;该直接基类的成员又含有它本身继承的基类的成员;依次类推直至继承链的顶端。因此,最终的派生类将继承它的直接基类的子对象和数据以及其基类继承来的一层层基类的子对象和数据
注意:🎯
一个类在继承一个派生类为基类时,不能同时继承此派生类的基类为基类 会导致歧义性解析(两个基类中可能有同样名字的成员函数)
例如:
class Base {..............};
class D1 : public Base {..............};
class D2 : public Base public D1 {........................};
公有派生和私有派生
在继承声明语句中,访问控制关键字用于说明在基类定义中所声明的成员和成员函数能够在多大范围内被派生类所访问当一个类派生自基类,该基类可以被继承为public
、protected
或private
三种类型。继承类型是通过上面讲解的访问修饰符(access-specifier)来指定的,注意,我们几乎不使用protected
或private
访问控制关键字进行类的继承,通常使用public
继承, 当使用不同类型的继承时,遵循以下几个规则:
公有继承(public):当一个类派生自公有基类时基类的公有成员继承后也是派生类的公有成员 ,基类的保护成员继承后也是派生类的保护成员 ,基类的私有成员继承后不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员 将成为派生类的保护成员 ,且基类的私有成员不能直接被派生类访问
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员(所有成员) 将成为派生类的私有成员,且基类的私有成员不能直接被派生类访问
将公有继承和私有继承的具体区别列表如下
通过上表,我们可以将两种派生的特点总结如下:
1.无论哪种派生方式,基类中的private成员在派生类中都是不可见的,也就是说,基类中的private成员不允许外部函数或派生类中的任何成员访问
2.派生类public派生与private派生的不同点在于基类中的public成员在派生类中的访问属性:
public派生时(派生类访问控制关键字为public ),基类中的public成员相当于派生类中的public成员(也就是说把基类中为public的允许派生类正常访问 基类中为private访问权限的成员不允许被派生类访问)
private派生时(派生类访问控制关键字为private), 基类中的public成员相当于派生类中的private成员 (也就是说把基类中所有成员不论public还是private访问权限的 都看作private私有访问权限)
总结:🎯
派生类可以访问基类中所有的非私有成员,因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为其成员为private
属性
注意:🎯
一个派生类继承了所有的基类方法,但派生类不继承基类的下列成员:
1.基类的构造函数、析构函数和拷贝构造函数
2.基类的重载运算符
3.基类的友元函数
案例 使用类的继承编写一个区别 猴子和鱼 的程序
#include <iostream>
using namespace std;
class Animal
{
public:
string name;
string mouth;
void eat();
void sleep();
void jump();
};
class looklike
{
public:
string color;
string size;
};
class monkey :public Animal , public looklike//多重类继承
{
public:
void climb();
};
class fish :public Animal
{
public:
void swim();
};
void Animal::eat()
{
cout << "我在吃东西呢" << endl;
}
void Animal::sleep()
{
cout << "我在睡觉 别来打扰我" << endl;
}
void Animal::jump()
{
cout << "我跳的高不高" << endl;
}
void monkey::climb()
{
cout << "我是一只小皮猴 我是爬树小能手" << endl;
}
void fish::swim()
{
cout << "我是一条小鲤鱼 正在游来游去 " << endl;
}
int main()
{
monkey monkey;
fish fish;
monkey.name = "猴子";
fish.name = "小鱼";
monkey.color = "棕色的";
cout <<"这是一只"<< monkey.color <<monkey.name <<endl;
monkey.eat();
fish.eat();
monkey.climb();
fish.swim();
}
结果:
扩展
友元类和友元函数 保护成员与保护派生🔍
基类和派生类在对象之间不存在类型转换 派生类和基类之间的类型转换🔍
基类与派生类的指针强制转换 派生类覆盖基类成员 指针对象和对象的区别🔍