1.
类之间的关系:
has-A:包含关系,用以描述一个类由多个“部件类”构成。实现has-A关系用成员表示,即一个类中的数据成员是另一种已经定义的类。
uses-A:一个类部分地使用另一个类。通过类之间成员函数的相互联系,定义友元或对象参数传递实现。
is-A:机制称为“继承”。关系具有传递性,不具有对称性。
继承是类之间定义的一种重要关系,一个 B 类继承A类,或称从类 A 派生类 B,类 A 称为基类(父类),类 B 称为派生类(子类)
类继承关系的语法形式:
class 派生类名 : 基类名表
{
数据成员和成员函数声明
};
基类名表的构成:访问控制 基类名1, 访问控制 基类名2 ,… , 访问控制 基类名n
公有继承:基类的公有成员是派生类的公有成员,基类的保护成员是派生类的保护成员
私有继承:基类的公有成员和保护成员是派生类的私有成员
保护继承:基类的公有成员和保护成员是派生类的保护成员
不论何种方式继承基类,派生类都不能直接使用基类的私有成员
2.
公有继承:
#include<iostream>
using namespace std ;
class A
{ public :
void get_XY() { cout << "Enter two numbers of x, y : " ; cin >> x >> y ; }
void put_XY() { cout << "x = "<< x << ", y = " << y << '\n' ; }
protected: int x, y ;//保护数据成员在类层次中可见
};
class B : public A
{ public :
int get_S() { return s ; };
void make_S() { s = x * y ; }; // 使用基类数据成员x,y
protected: int s;//保护数据成员在类层次中可见
};
class C : public B
{ public :
void get_H() { cout << "Enter a number of h : " ; cin >> h ; }
int get_V() { return v ; }
void make_V() { make_S(); v = get_S() * h ; } // 使用基类成员函数
protected: int h, v;//保护数据成员在类层次中可见
};
int main()
{ A objA ;
B objB ;
C objC ;
cout << "It is object_A :\n" ;
objA.get_XY() ;
objA.put_XY() ;
cout << "It is object_B :\n" ;
objB.get_XY() ;
objB.make_S() ;
cout << "S = " << objB.get_S() << endl ;
cout << "It is object_C :\n" ;
objC.get_XY() ;
objC.get_H();
objC.make_V() ;
cout << "V = " << objC.get_V() << endl ;
}
3.私有继承:
#include<iostream>
using namespace std ;
class A
{ public :
void get_XY() { cout << "Enter two numbers of x and y : " ; cin >> x >> y ; }
void put_XY() { cout << "x = "<< x << ", y = " << y << '\n' ; }
protected: int x, y ;
};
class B : private A
{ public :
int get_S() { return s ; }
void make_S() { get_XY(); s = x * y ; }//调用基类成员函数,访问私有数据成员
private: int s ;
};
int main()
{ B objB ;
cout << "It is object_B :\n" ;
objB.make_S() ;
cout << "S = " << objB.get_S() << endl ;
}
4.私有数据成员的测试:
#include<iostream>
using namespace std ;
class A
{ public: A(){ x=1; }
int out() {return x ; }
void addX() { x++; }
private: int x ;//基类的私有数据成员不能在派生类中直接访问,但派生类对象会建立私有数据空间
} ;
class B : public A
{ public: B(){ y=1; }
int out() {return y ; }
void addY() { y++; }
private: int y ;
} ;
int main()
{ A a ;
cout << "a.x=" << a.out() << endl ;
B b ;//创建派生类对象调用构造函数b.x = 1 b.y = 1
b.addX() ; b.addY() ;
cout << "b.x=" << b.A::out() << endl ;//调用基类版本同名函数返回 b.x 的值
cout << "b.y=" << b.out() << endl ;//调用派生类版本同名函数返回 b.y 的值
}
5.
重名成员派生类定义了与基类同名的成员,在派生类中访问同名成员时屏蔽了基类的同名成员
在派生类中使用基类的同名成员,显式地使用类名限定符:类名 :: 成员
基类成员的作用域延伸到所有派生类,派生类的重名成员屏蔽基类的同名成员
#include<iostream>
using namespace std ;
class A
{ public:
int a1, a2 ;
A( int i1=0, int i2=0 ) { a1 = i1; a2 = i2; }
void print()
{ cout << "a1=" << a1 << '\t' << "a2=" << a2 << endl ; }
};
class B : public A
{ public:
int b1, b2 ;
B( int j1=1, int j2=1 ) { b1 = j1; b2 = j2; }
void print() //定义同名函数
{ cout << "b1=" << b1 << '\t' << "b2=" << b2 << endl ; }
void printAB()
{ A::print() ; //派生类对象调用基类版本同名成员函数
print() ; //派生类对象调用自身的成员函数
}
};
int main()
{ B b ; b.A::print(); b.printAB(); }
派生类也是基类,基类指针可以指向派生类对象派生类中定义与基类同名的成员函数,称为重载成员函数
6.
派生类中访问静态成员:
基类定义的静态成员,将被所有派生类共享
派生类中访问静态成员,用以下形式显式说明:类名 :: 成员 或 对象名 . 成员
#include<iostream>
using namespace std ;
class B
{ public:
static void Add() { i++ ; }
static int i;
void out() { cout<<"static i="<<i<<endl; }
};
int B::i=0;//静态变量在此定义
class D : private B
{ public:
void f()
{ i=5;//i 是类D的私有静态数据成员类中可见
Add();//Add()是类D的私有静态成员函数类中可调用
B::i++;
B::Add();
}
};
int main()
{
B x; D y;
x.Add();
x.out();
y.f();
cout<<"static i="<<B::i<<endl;
cout<<"static i="<<x.i<<endl;
//cout<<"static i="<<y.i<<endl;错误,i是类D的私有静态数据成员
}
7.基类的初始化:
C++提供一种机制,在创建派生类对象时用指定参数调用基类的构造函数来初始化派生类继承基类的数据
派生类构造函数声明为:派生类构造函数 ( 变元表 ) : 基类 ( 变元表 ) , 对象成员1( 变元表 )… 对象成员n ( 变元表 ) ;
构造函数执行顺序:<1>基类<2>对象成员<3>派生类
#include<iostream>//带参数构造函数调用顺序测试
using namespace std ;
class parent_class
{ int data1 , data2 ;
public :
parent_class ( int p1 , int p2 )//基类有一个参数化的构造函数
{ data1 = p1; data2 = p2; }
int inc1 () { return ++ data1; }
int inc2 () { return ++ data2 ; }
void display () {cout << "data1=" << data1 << " , data2=" << data2 << endl ; }
};
class derived_class : private parent_class
{ int data3 ;
parent_class data4 ;
public:
derived_class ( int p1 , int p2 , int p3 , int p4 , int p5 ): parent_class ( p1 , p2 ) , data4 ( p3 , p4 )
{ data3 = p5 ; }
int inc1 ( ) { return parent_class :: inc1 ( ) ; }
int inc3 ( ) { return ++ data3 ; }
void display ( )
{ parent_class :: display ( ) ; data4.display ( ) ;
cout << "data3=" << data3 << endl ;
}
} ;
int main ( )
{ derived_class d1 ( 17 , 18 , 1 , 2 , -5 ) ; d1 . inc1 ( ) ; d1 . display ( ) ; }
8.类继承和类包含的比较:
//用继承方式设计Point类和Circle类
#include<iostream>
using namespace std ;
class Point
{ public :
Point(double t1, double t2) { x=t1; y=t2;}
void OutPoint() { cout << "Point: x=" << x << " y=" << y << endl ; }
protected : double x, y;
};
class Circle : public Point //Circle类继承Point类
{ public:
Circle(double t1,double t2, double t3) : Point(t1,t2) { radius = t3 ; }
void OutCircle()
{ Point::OutPoint(); cout << "radius=" << radius << endl ; }
protected: double radius; //派生类数据成员
};
int main()
{ Circle c( 0, 0, 12.5 ) ;
c.OutPoint() ; //调用从基类Point继承的成员函数
c.OutCircle() ; //调用Circle类成员函数
}
//用包含方式设计Point类和Circle类
#include<iostream>
using namespace std ;
class Point
{ public :
Point(double t1, double t2) { x=t1; y=t2;}
void OutPoint() { cout << "Point: x=" << x << " y=" << y << endl ; }
protected : double x, y;
};
class Circle
{ public:
Circle(double t1,double t2, double t3) : centre(t1,t2) { radius = t3 ; }
void OutCircle()
{ centre.OutPoint(); cout << "radius=" << radius << endl ; }
Point centre; //包含Point成员
protected: double radius;
};
int main()
{ Circle c( 0, 0, 12.5 ) ;
c.centre.OutPoint() ; //通过成员centre调用Point的成员函数
c.OutCircle() ; //调用Circle类成员函数
}
9.多继承:
一个类有多个直接基类的继承关系称为多继承,多继承声明语法:
class 派生类名 : 访问控制 基类名1 , 访问控制 基类名2 , … , 访问控制 基类名n
{
数据成员和成员函数声明
};
多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员。
执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定义派生类时指定的各个继承基类的顺序。
class Base1
{ public:
Base1(int x) { value = x ; }
int getData() const { return value ; }
protected:
int value;
};
class Base2
{ public:
Base2(char c) { letter=c; }
char getData() const { return letter;}
protected:
char letter;
};
class Derived : public Base1, public Base2
{ friend ostream &operator<< ( ostream &, const Derived & ) ;
public :
Derived ( int, char, double ) ;
double getReal() const ;
private :
double real ;
};
int main()
{ Base1 b1 ( 10 ) ;
Base2 b2 ( 'k' ) ;
Derived d ( 5, 'A', 2.5 ) ;
return ;
}
10.虚继承:
如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。
如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象。
要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。
虚继承声明使用关键字: virtual
class B { public : int b ;} ;
class B1 : virtual public B { private : int b1 ; } ;
class B2 : virtual public B { private : int b2 ; } ;
class C : public B1 , public B2
{ private : float d ; } ;
由于类 C 的对象中只有一个 B 类子对象,名字 b 被约束到该子对象上,所以,当以不同路径使用名字 b 访问 B 类的子对象时,所访问的都是那个唯一的基类子对象。即
cc . B1 :: b 和 cc . B2 :: b 引用是同一个基类 B 的子对象
#include<iostream>
using namespace std ;
class A
{ public :
A ( ) { cout << "class A" << endl ; }
} ;
class B : public A
{ public :
B ( ) {cout << "class B" << endl ; }
} ;
class C : public A
{ public :
C ( ) {cout << "class C" << endl ; }
} ;
class D : public B , public C
{ public :
D ( ) {cout << "class D" << endl ; }
} ;
int main ( )
{ D dd ; }//一次调用A的构造函数ABCD
#include<iostream>
using namespace std ;
class A
{ public :
A ( ) { cout << "class A" << endl ; }
} ;
class B : public A
{ public :
B ( ) {cout << "class B" << endl ; }
} ;
class C : public A
{ public :
C ( ) {cout << "class C" << endl ; }
} ;
class D : public B , public C
{ public :
D ( ) {cout << "class D" << endl ; }
} ;
int main ( )
{ D dd ; }//两次调用A的构造函数ABACD