耦合度,高内聚,低耦合
程序设计追求高内聚,低耦合
高内聚指一个函数干的事情极少,甚至只干一件事情
低耦合是类之间的关系越少越好
继承
继承的耦合度很高,但是方便不用写太多代码
在 C++中可重用性(software reusability)是通过继承(inheritance)这一机制来 实现的。
定义:
类的继承,是新的类从已有类那里得到已有的特性。或从已有类产生新类 的过程就是类的派生。原有的类称为基类或父类,产生的新类称为派生类或子类。
派生与继承,是同一种意义两种称谓。
#include <iostream>
using namespace std;
class Student
{
public:
void dis() {
cout<<name<<endl;
cout<<age<<endl;
}
string name;
int age;
};
class Student2:public Student
{
public:
Student2(string n,int a,char s,float f)
{
name = n; age = a; sex = s; score = f;
}
void dis() {
Student::dis();
cout<<sex<<endl;
cout<<score<<endl;
}
char sex;
float score;
};
派生类的组成
派生类中的成员,包含两大部分,一类是从基类继承过来的,一类是自己增加 的成员。从基类继承过过来的表现其共性,而新增的成员体现了其个性。
![20988794-5f4f930f1c10d98d.png](https://i-blog.csdnimg.cn/blog_migrate/90865886d73f060caedab2f9da62cca0.png)
几点说明: 1,全盘接收,除了构造器与析构器。基类有可能会造成派生类的成员冗余,所以 说基类是需设计的。
2,派生类有了自己的个性,使派生类有了意义。
派生类的构造函数是一定会调用基类的构造函数的,一般都是将继承过来的变量用初始化列表来初始化。如果不想写初始化列表的话,基类要有无参构造函数。
一个派生类可以同时有多个基类,这种情况称为多重继承,派生类只有一个 基类, 称为单继承。
继承的方式
语法:
class 派 类名:[继承 式] 基类名 {
派 类成员声明;
};
public公有继承:
当类的继承方式为公有继承时,基类的公有和保护成员的访问属性在派生
类中 不变,而基类的私有成员不可访问。
protected保护继承:
保护继承中,基类的公有成员和私有成员都以保护成员的身份出现在派生
类 中,而基类的私有成员不可访问。
private私有继承:
当类的继承方式为私有继承时,基类中的公有成员和保护成员都以私有成
员身 份出现在派生类中,而基类的私有成员在派生类中不可访问。
private成员在子类中依然存在,但是却无法访问到。不论何种方式继承 基类,派生类都不能直接使用基类的私有成员 。
#include <iostream>
using namespace std;
class A
{
private:
int a;
protected:
int b;
public:
int c;
A() {
a = 0;
b = 0;
c = 0;
}
void set(int a, int b, int c)
{
this->a = a;
this->b = b;
this->c = c;
}
};
class B : public A
{
public:
void print()
{
cout<<"a ="<<a<<endl; //不能访问,a是基类的private
cout<<"b ="<<b<<endl;
cout<<"c ="<<c<<endl;
}
};
class C : protected A
{
public:
void print()
{
cout<<"a ="<<a<<endl; //不能访问,a是基类的private
cout<<"b ="<<b<<endl;
cout<<"c ="<<c<<endl;
}
};
class D : private A
{
public:
void print()
{
cout<<"a = "<<a<<endl; //不能访问,a是基类的private
cout<<"b = "<<b<<endl;
cout<<"c = "<<c<<endl;
} };
int main(void)
{
A aa;
B bb;
C cc;
D dd;
aa.c = 100;
bb.c = 100;
cc.c = 100;
dd.c = 100;
aa.set(1, 2, 3);
bb.set(10, 20, 30);
cc.set(40, 50, 60); //不能访问,set是protected成员
dd.set(70, 80, 90); //不能访问,set是private成员
bb.print();
cc.print();
dd.print();
return 0;
}
类型兼容性原则
类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类 的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之 外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能 解决的问题,公有派生类都可以解决。
类型兼容规则中所指的替代包括以下情况:
子类对象可以当作父类对象使用
子类对象可以直接赋值给父类对象
子类对象可以直接初始化父类对象
父类指针可以直接指向子类对象
父类引用可以直接引用子类对象
在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。
子类就是特殊的父类 (base *p = &child;)
#include <iostream>
using namespace std;
class Parent
{
public:
void printP()
{
cout << "parent...." << endl;
}
};
class Child : public Parent
{
public:
void printC()
{
cout << "child..." << endl;
}
};
void print01(Parent *p)
{
p->printP();
}
void print02(Parent &p)
{
p.printP();
}
int main() {
/*
//Parent p;
//Child c=p; //p对象填充不满c对象空间
Child c;
Parent p=c; //c对象所占用的内存空间>=p对象占用空间,能够填充满p对象所需要空间
*/
Child c1;
c1.printC();
Parent *p = NULL; //可以用父类指针指向子类对象
p = &c1;
p->printP(); //执行父类的函数
Child c2;
Parent p2;
print01(&p2);
print01(&c2); // 父类指针指向子类对象
print02(p2);
print02(c2); // 父类引用指向子类对象
//第二层含义 用子类初始化父类对象
Child c3;
Parent p3 = c3;
return 0;
}
继承中的构造和析构
在子类对象构造时,需要调用父类构造函数对其继承得来的成员进行初始化.
在子类对象析构时,需要调用父类析构函数对其继承得来的成员进行清理.
继承中构造析构调用原则:
1、子类对象在创建时会首先调用父类的构造函数
2、父类构造函数执行结束后,执行子类的构造函数
3、当父类的构造函数有参数时,需要在子类的初始化列表中显示调用
4、析构函数调用的先后顺序与构造函数相反
先构造父类,再构造成员变量、最后构造自己
先析构自己,在析构成员变量、最后析构父类
#include <iostream>
using namespace std;
class Object
{
public:
Object(const char* s)
{
cout<<"Object()"<<" "<<s<<endl;
}
~Object() {
cout<<"~Object()"<<endl;
}
};
class Parent : public Object
{
public:
Parent(const char* s) : Object(s)
{
cout<<"Parent()"<<" "<<s<<endl;
}
~Parent() {
cout<<"~Parent()"<<endl;
}
};
class Child : public Parent
{
public:
Child() : o2("o2"), o1("o1"), Parent("Parameter from Child!")
{
cout<<"Child()"<<endl;
}
~Child() {
cout<<"~Child()"<<endl;
}
private:
Object o1;
Object o2; };
void run() {
Child child;
}
int main(int argc, char *argv[])
{
run();
return 0;
}
运行结果:
Object() Parameter from Child!
Parent() Parameter from Child!
Object() o1
Object() o2
Child()
~Child()
~Object()
~Object()
~Parent()
~Object()
继承中同名成员变量处理方法
1、当子类成员变量与父类成员变量同名时
2、子类依然从父类继承同名成员
3、在子类中通过作用域分辨符::进行同名成员区分(在派生类中使用基
类的同名成员,显式地使用类名限定符)
4、同名成员存储在内存中的不同位置
派生类中的static关键字
1.基类定义的静态成员,将被所有派生类共享
- 根据静态成员自身的访问特性和派生类的继承方式,在类层次体系中具 有不同的访问性质 (遵守派生类的访问控制)
3.派生类中访问静态成员,用以下形式显式说明:
类名 :: 成员
或通过对象访问:对象名 . 成员
多继承与虚继承
多继承
class C:public c1, public c2 {}
虚继承virtual
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象
要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。
虚继承声明使用关键字 virtual
如:class B1: virtual public B { }