c++那些事儿3 0 继承

211 阅读5分钟
    一般形式   
	 class class_name:继承方式 基类名{ code   }
		 继承方式有三种: public ,protected,private.   //java好像都是public继承。
     单继承
     多继承,多继承会很复杂,所以java,c sharp都采用interface。
  类函数:
     构造函数
	       先执行父类的构造函数,在执行子类的构造函数。
		   一般形式  派生类的构造函数(参数列表):基类构造函数名(参数列表}{ code}
	 析构函数
	       先构造的后析构,后构造的先析构。
	 虚函数。
	 避免二义性。但是最后的派生类不仅负责对直接基类初始化,还要对虚基类初始化。

**看code是最有用的,细节情况已经注释说明。**
``` #include #include using namespace std; // 类A class A { protected: string name; int id; double da; private: double pa; //这个数据继承后不能被访问 public: A(string name, int id) { cout << "A的构造函数执行"<name = name; //this指针 this->id = id; this->da = da; }
 void setDa(double d) {
	 da = d;
 }

 ~A() {
	 cout << "A的析构函数"<<endl;
 }

void setId(int id) {

//id是私有数据成员,不能被继承,类外不能访问,通过函数才能 this->id = id; }

 void print() {
	 cout << "string=" << name << "  " << "id=" << id<< endl;
 }

}; // 注意 C++中类的结尾是有;的,和java不同,我vs,ide编辑没有在意。

//如果不写关键字,默认为private。 class B :virtual public A { //B类public继承A类,但是私有数据成员不能访问。 protected: int id; //A类的id成员被覆盖了。

public: /* 父类构造函数的初始化通过子类构造函数初始化列表实现, */

  B(string na,int ida,int idb):A(na,ida){
	  cout << "B的构造函数执行"<<endl;
	  this->id = idb;
  }
  ~B() {
	  cout << "B的析构函数"<<endl;
  }

  void  print() {
	  /*
	  基类同名的数据成员在派生类被覆盖,成为不可见。
	  */
	  cout << "A类被继承的ID:" << A::id << endl;
	  cout <<"name:B"<< name<<" "<<"id:"<<id<<endl; //name是继承A的。
  }

};

class C:virtual public A{

//B类public继承A类,但是私有数据成员不能访问。

protected: int id;

public: /* 父类构造函数的初始化通过子类构造函数初始化列表实现, */ C(string na,int ida,int idc) :A(na,ida) { cout << "C的构造函数执行" << endl; this->id = idc; } ~C() { cout << "C的析构函数" << endl; }

void  print() {
	cout << "name:C" << name << " " << "id:" << id << endl;; //name是继承A的。
	
}

};

//D类继承B,C, 因为B,C都继承A,所以D类有2份A,这样就会出现二义性问题。 class D :public B,public C { public: void showId() { /* cout << "id::" << id << endl; 如果这样,就会产生二义性,D公有继承了B,C protedted的id, 这里不知道访问哪一个。 但是可以通过域运算符指定A,B,C继承来的id。 */ cout << "id::A" <<A::id << endl; //通过域运算符指定id。 }

 /*
  D继承了,B,C。B,C继承了A,即继承了double da;
  怎么访问它了。
      cout<<da;
	  cout<<A::da; 都不行,无法指出是继承B的,还是C的。
	   所以就要虚基类了。
 */
 void showDa() {

	 cout << "B::da" << B::da << endl;
 }
 /*
 在以前派生类只对其直接基类初始化,在由其直接子类对间接子类初始化
 现在由于虚基类在派生类只有一份拷贝,所以这份数据必须由派生类给出。
 因为类B,类C可能给出不同的构造函数,这样对虚基类初始化会产生矛盾。
 */

 D(string na, int ida, int idc) :C(na, ida, idc),
	 B(na, ida, idc), A(na, ida)
 {
	 cout << "D的构造函数执行" << endl;
 }
 ~D() {
	 cout << "D的析构函数" << endl;
 }

};

int main() {

A a("name_A", 111);
a.print();
cout << "-----------------------------" << endl;
//先执行父类的构造函数,在执行基类的构造函数
B b("name_B",111, 222);
//这里是B的id,因为private属性在子类不能访问。
b.print();
cout << "-----------------------------" << endl;
C c("name_C", 111, 333);
//这里是B的id,因为private属性在子类不能访问。
c.print();
cout << "-----------------------------" << endl;


D d("name_D", 111, 444);

// id的二义性 可以通过 ::域运算符指定,解决。
   d.showId();

 // 准备验证double da; 产生二义性的情况,这个就只能通过虚基类确定。
  //   setDa() 是会产生二义性的函数,但是A是虚基类。
   d.setDa(3.1415926);
   d.showDa();
   cout << "-----------------------------" << endl;


 system("pause");  //vs要看析构函数要去掉这一句。
return 0;

}

<hr>
>*结果如下,可以对照代码分析*
![结果图.PNG](http://upload-images.jianshu.io/upload_images/4976516-462150689d7b40a6.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

>这里main函数的代码如下:


int main() { D d("name_D", 111, 444); // id的二义性 可以通过 ::域运算符指定,解决。 d.showId();

 // 准备验证double da; 产生二义性的情况,这个就只能通过虚基类确定。
  //   setDa() 是会产生二义性的函数,但是A是虚基类。
   d.setDa(3.1415926);
   d.showDa();
   cout << "-----------------------------" << endl;

                                 /*  vs选择开始执行但不调试 */
// system("pause");  //vs要看析构函数要去掉这一句。
return 0;

}

<hr>
>**构造函数和析构函数执行顺序验证**
![只保留了D类.PNG](http://upload-images.jianshu.io/upload_images/4976516-b583b24e331c8b42.PNG?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

<hr>
**东西好多啊,c++ 讲个语法就不少东西了**
>      虚函数,多态性,这个代码挖了坑,后面在讲,好累啊。