一般形式
class class_name:继承方式 基类名{ code }
继承方式有三种: public ,protected,private. //java好像都是public继承。
单继承
多继承,多继承会很复杂,所以java,c sharp都采用interface。
类函数:
构造函数
先执行父类的构造函数,在执行子类的构造函数。
一般形式 派生类的构造函数(参数列表):基类构造函数名(参数列表}{ code}
析构函数
先构造的后析构,后构造的先析构。
虚函数。
避免二义性。但是最后的派生类不仅负责对直接基类初始化,还要对虚基类初始化。
看code是最有用的,细节情况已经注释说明。
#include<iostream>
#include<string>
using namespace std;
// 类A
class A {
protected:
string name;
int id;
double da;
private:
double pa; //这个数据继承后不能被访问
public:
A(string name, int id) {
cout << "A的构造函数执行"<<endl;
this->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;
}
结果如下,可以对照代码分析
这里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;
}
构造函数和析构函数执行顺序验证
东西好多啊,c++ 讲个语法就不少东西了
虚函数,多态性,这个代码挖了坑,后面在讲,好累啊。