继承:
/*以下的使用区域分别是1、在main函数创建对象调用的时候例如 son. s;s.say(),和 2、void son::show(){say()};这两种情况
public继承:在基类中如果参数是
public格式:那么在派生类中,则是public类型,在创建的对象和调用的函数中都可以访问;
private 格式:那么在派生类中,则也是private类型,在创建的对象和调用函数中都不可以访问;
protected 格式:那么在派生类中,在创建的对象不可以访问,调用函数可以访问;
private继承:在基类中如果参数是
public 格式:在派生类中,创建的对象无法直接访问,在类函数中可以访问;
private 格式:那么在派生类中,也是private类型,在创建的对象和调用函数中都不可以访问;
protected 格式:在派生类中,在创建的对象不可以访问,类函数中可以访问;
protected继承:在基类中如果参数是
public 格式: 在派生中,创建的对象无法直接访问,在类函数中可以访问;
private 格式:在派生中,创建的对象和类函数中都不可以访问;
protected 格式:在派生中,在创建的对象中无法访问,在类函数可以访问;
总结: public private protected
public继承 对象Y函数Y 对象N函数N 对象N函数Y
private继承 对象N函数Y 对象N函数N 对象N函数Y
protected继承 对象N函数Y 对象N函数N 对象N函数Y
#include <iostream>
using namespace std;
class A{
protected:
int score;
public:
void setscore(int );
};
void A::setscore(int s)
{
score=s;
}
class B:private A{
private:
int id;
public:
void setid(int );
void getid();
void getscore();
};
void B::setid(int i)
{
id=i;
}
void B::getid()
{
cout<<id<<endl;
setscore(87);
}
void B::getscore(){cout<<score<<endl;}
int main()
{
B b;
b.score=98;
b.setscore(98);
b.setid(1);
b.getid();
b.getscore();
}
函数遮蔽:
函数遮蔽是指,例如在基类中
class A{
public:
void show();
};
在派生类中:
class B:public A{
public:
void show(int a);
};
在基类和派生类中都有一个函数show()函数 虽然在基类中,show()并没有参数,而在派生类中有int参数,但是还是遮蔽,在main函数中:
int main()
{
B b;
b.show();
从函数的重载定义的话 这边应该是调用 基类函数中,但是因为遮蔽这边调用的是派生类中,
这段代码虽然编译是出错的 因为函数不匹配,出错的会告诉我们备用的函数是void show(int a);说明编译器无法跟踪到 上面一个函数;
****当然如果一个函数中 有两个函数名一样的话 那就不是遮蔽了,是重载,编译器会根据你给的参数匹配函数。
继承的内存区域:
基类的内存大小取决于其,定义的参数的长度:
例如:
class A{
private:
char a;
int b;
public:
void show();
};
这个基类的长度就是 8;代码存在代码段。
在派生类中:
class B:public A{
int a;
};
派生类的长度是12;不仅包含了自身的长度 还继承了他基类的长度;
构造函数的使用:
当在派生函数中使用,基类函数的构造函数的时候,必须在参数列表中调用,因为派生类无法继承基类的构造函数,具体的使用代码如下;
class A{
private:
char a;
int b;
public:
A(char ,int);
void show();
};
class B:public A{
private:
int d;
public:
B:
};
B:B(char a,int b,int c):A(a,b ),d(c){}
**1、此外需要强调的是,在参数列表中,是调用A这个函数 所以这里的a,b是实参,不需要带上类型,跟正常的函数调用是一样的。
2、当有多层派生关系的时候,要层层递进,例如A->B,C->D,使用构造函数时,D对B和C进行调用构造函数,B C再对A进行参数调用,这又会有一个B C谁初始化成功的问题,按出现的顺序来,谁最后初始化就是那个参数赋值成功;
3、析构函数的顺序跟,构造函数是相反的比如书,A->B->C 那么析构的顺序就是C->B->A;
多继承的情况下:构造函数执行的顺序跟,定义的顺序是一样的。析构的顺序是相反的:
例如:
class C:pubic B,pubic A,pubic C
这里构造的顺序就是B->A->C 析构的顺序 就是C->A->B;
虚继承与虚基类:
在派生类中因为,可能会友菱形派生方式,A->B,C->D;
按照派生的内存分配,在B,C中都有A的参数 比如说A中有一个a;
那么在B,C中都有a,在D中如果你去调用这个a 那么编译器就会报出一个错误,无法确认这个a是哪个里面的,可能是B也可能是C,由此 引出概念,虚继承,在继承的前面加上virtual修饰,那么就表示这两个,类愿意共享这个a就不会出现,歧义的情况;
代码如下:
#include <iostream>
using namespace std;
class A{
protected:
int m_a;
public:
A(int a);
};
A::A(int a):m_a(a){}
class B:public A{
protected:
int m_b;
public:
B(int ,int);
};
B::B(int a,int b):A(a),m_b(b){}
class C: public A{
protected:
int m_c;
public:
C(int ,int);
};
C::C(int a,int c):A(a),m_c(c){}
class D:public C,public B{
public:
D(int,int,int,int);
void say();
private:
int m_d;
**在这里用构造函数的时候 跟普通的继承有很大的区别,在普通的继承中,D需要调用B C的构造函数,然后B C 再分别调用A的构造函数,但是在这里,D直接调用A的构造函数,而且B C构造函数还是要对A进行构造,但是不起作用。
这就叫做构造函数是受间接基类影响,不是直接基类;
例如A ->B,C->D A是D的间接基类。