一、面向对象的三大特征
封装、继承、多态、(抽象)
封装:
将不同类型的数据已经与这些数据相关的操作构成一个集合,作为了一个新的数据类型,里面有一些是public(公共的)、private(私有的)、protected(保护的)。
所谓封装就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏.封装是面向对象的特征之一,是对象和类概念的主要特性. 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
继承:
所谓继承就是指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展. 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现.继承概念的实现方式有二类:实现继承与接口继承.实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
多态:
所谓多态就是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
多态的三个条件:有继承,有虚函数重写,有父类指针指向子类对象。
————————————————
版权声明:前文为CSDN博主「程序员小明丶」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_45372436/article/details/101034320
抽象
并不是特征,只是在描述现实世界时,将其某一事物或任务描述成类型的过程为抽象。
二、继承
–protected,private
1、继承的写法:
class 子类:继承权限 基类
{
};
没有写继承权限,默认是私有的继承,一般情况下不写私有继承
2、继承相关知识点:
1)一个类自动拥有了来自另外一个类的属性和方法;
2)一个类是一个类;
(谁是谁一般情况下是继承,谁有谁是组合)
是层次关系 —相区别于继承和派生,从上层说下层是派生,从下层说上层是继承。例如:A类派生除了B类,那么B类从A类继承过来。
3、继承特点
1)基类的除了构造和析构之外,其他的全盘继承
class A
{
public:
int m_i;
void print(){cout << "A::print " << endl;}
protected:
int m_j;
private:
int m_k;
};
class B:public A
{
};
class C:A
{
};
void main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;//全部被继承下来
B b;
C c;
b.print();
//c.print();//error,私有的继承,不能被访问
}
运行结果:
2)基类的权限
是否能被子类的成员函数访问?是否能被外界访问?
能被继承和能被访问是两个概念。
基类的权限 --- public --- protected --- private ---继承权限
||
public public protected private
protected protected preoteced private
private 不可访问 不可访问 不可访问
测试代码:
class A
{
public:
int m_i;
void print(){cout << "A::print " << endl;}
protected:
int m_j;
private:
int m_k;
};
class B:public A
{
public:
void set()
{
m_i = 10;
m_j = 20;
//m_k = 30;//error,私有的能被继承,不能被访问
}
};
class C:protected A //12个字节
{
public:
void test()
{
m_i = 10;
m_j = 20;
//m_k = 30;//error,私有的能被继承,不能被访问
}
};
class CC:protected C //12个字节
{
public:
void ff()
{
m_i = 10;
m_j = 20;
//m_k = 30;//error,私有的能被继承,不能被访问
}
};
class D:private A //12个字节
{
public:
void fn()
{
m_i = 10;
m_j = 20;
//m_k = 30;//error,私有的能被继承,不能被访问
}
};
class DD:protected D //12个字节
{
public:
void ff()
{
//都不可用,A是public和protected属性,被D私有化
//m_i = 10;
//m_j = 20;
//m_k = 30;//error,私有的能被继承,不能被访问
}
};
void main()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
cout << sizeof(C) << endl;//全部被继承下来
B b;
b.print();
b.m_i = 12;
//b.m_j = 12;//error,为私有
//b.m_k = 12;//error,为不可访问
C c;
//保护继承,都不能访问
//c.m_i = 10;//error
//c.m_j = 20;//error
//c.m_k = 30;//error
c.test();
}
4、继承三步骤:
1、除构造析构全盘接收
2、改写
3、添加子类特有
测试示例代码:
class A
{
public:
A(){cout << "A " << endl;}
~A(){cout << "~A " << endl;}
void print(){cout << "A::print " << endl;}
private:
int m_i;
};
class B:public A
{
public:
B(){cout << "B" << endl;}
~B(){cout << "~B" << endl;}
private:
int m_j;
};
void main()
{
B b;//结果为A B ~B ~A,先构造A,再构造B,先析构B,再析构A
}
其中两个类的内存布局:
运行结果:
所以构造子类对象,先要去调用基类的构造函数,再调用子类的构造函数。因为基类的除了构造和析构之外,其他的全盘继承。当构造子类B时,需要为B类里面的数据成员开辟内存空间,当前对象B类中有两个数据成员,一个是本身的m_j
,一个是从A类继承下来的m_i
,m_i
不是B类本身的数据成员,可以使用它,但没有对其的创造权,要去调用A类的构造函数。
并且子类B的内存布局中,继承下来的数据成员要先于其本身的数据成员,所以是先调用基类的构造函数,再调用自身的构造函数。
为什么没有将构造和析构继承下来?
因为没有对其的构造权
5、有继承和组合的构造顺序(部分,未考虑虚继承等)
1)先按照继承顺序调用基类的构造;
2)按照组合顺序调用组合的构造;
3)调用直接的构造;
代码示例:
class CPU
{
public:
CPU(){cout << "CPU" << endl;}
};
class KB//键盘
{
public:
KB(){cout << "KB" << endl;}
};
class Mouse
{
public:
Mouse(){cout << "Mouse" << endl;}
};
//Laptop特有的,这里用触摸屏示例
class Touch
{
public:
Touch(){cout << "Touch" << endl;}
};
class Computer
{
public:
Computer(){cout << "Computer" << endl;}
private:
//组合关系-有
CPU cpu;
KB kb;
Mouse ms;
};
class Laptop:public Computer//笔记本 继承关系-是
{
public:
Laptop(){cout << "Laptop" << endl;}
private:
Touch touch;
};
void main()
{
Laptop lt;
}
运行结果:
图形化理解:
构造顺序
6、继承的构造函数调用示例:
欲实现:
class Person
{
public:
private:
int m_num;
char *m_name;
char m_sex;
};
class Student:public Person
{
public:
private:
float m_score;//分数
};
void main()
{
Student s1(1001,"yasuo",'f',90);
//s1.print();//实现
}
示例代码:
class Person
{
public:
Person(int num=0,const char *name = " ",char sex = 'f'):m_num(num),m_sex(sex)
//Person(int num,const char *name,char sex):m_num(num),m_sex(sex)
{
m_name = new char[strlen(name) + 1];
strcpy_s(m_name,strlen(name) + 1,name);
}
void show()
{
cout << m_num <<" "<< m_name<<" " << m_sex <<" ";
}
~Person()
{
if(m_name != NULL)
{
delete[]m_name;
m_name = NULL;
}
}
private:
int m_num;
char *m_name;
char m_sex;
};
class Student:public Person
{
public:
Student(int num=0,const char *name = "xx",char sex = 'f',float score = 0.0):Person(num,name,sex),m_score(score)
//Person(num,name,sex)显示的调用当前基类的构造函数
//Student(int num,const char *name,char sex,float score):Person(num,name,sex),m_score(score)
{
}
void print()
{
show();
cout << m_score << endl;
}
private:
float m_score;//分数
};
void main()
{
Student s1(1001,"yasuo",'f',90);
s1.print();
Student s2;
s2.print();
}
运行结果:
构造函数有参无参构造相关问题:
对于代码:
其中的Student s;
无法实现,因为其为无参的构造,而类本身没有自己定义构造函数,而其基类的构造函数为自己定义的有参构造函数。而对Sudent类进行构造新类时,调用其默认构造函数之前,会先去调用基类的构造函数,导致出错。
class Person
{
public:
Person(char* name,char sex,int age){}
private:
char *m_name;
char m_sex;
int m_age;
};
class Student:public Person
{
};
void main()
{
Student s;//error
}
解决方法一:
解决方法二:
解决方案3
有参构造函数带上默认值
6、继承的拷贝构造函数示例:
class Person
{
public:
Person(int num=0,const char *name = " ",char sex = 'f'):m_num(num),m_sex(sex)
//Person(int num,const char *name,char sex):m_num(num),m_sex(sex)
{
m_name = new char[strlen(name) + 1];
strcpy_s(m_name,strlen(name) + 1,name);
}
void show()
{
cout << m_num <<" "<< m_name<<" " << m_sex <<" ";
}
Person(Person& p):m_num(p.m_num),m_sex(p.m_sex)
{
m_name = new char[strlen(p.m_name) + 1];
strcpy_s(m_name,strlen(p.m_name) + 1,p.m_name);
}
~Person()
{
if(m_name != NULL)
{
delete[]m_name;
m_name = NULL;
}
}
private:
int m_num;
char *m_name;
char m_sex;
};
class Student:public Person
{
public:
Student(int num=0,const char *name = "xx",char sex = 'f',float score = 0.0):Person(num,name,sex),m_score(score)
//Person(num,name,sex)显示的调用当前基类的构造函数
//Student(int num,const char *name,char sex,float score):Person(num,name,sex),m_score(score)
{
}
void print()
{
show();
cout << m_score << endl;
}
Student(Student& s):Person(s)
{
m_score = s.m_score;
}
private:
float m_score;//分数
};
void main()
{
Student s1(1001,"yasuo",'f',90);
s1.print();
Student s2;
s2.print();
Student s3(s1);
s3.print();
}
运行结果: