class D{......};
class B: public D{......};
class A: public D{......};
class C: public B, public A{.....};
这个继承会使D创建两个对象,要解决上面问题就要用虚拟继承格式
格式:class 类名: virtual 继承方式 父类名
class D{......};
class B: virtual public D{......};
class A: virtual public D{......};
class C: public B, public A{.....};
虚继承--(在创建对象的时候会创建一个虚表)在创建父类对象的时候
A:virtual public D
B:virtual public D
实例:
#include <iostream>
using namespace std;
//基类
class D
{
public:
D(){cout<<"D()"<<endl;}
~D(){cout<<"~D()"<<endl;}
protected:
int d;
};
class B:virtual public D
{
public:
B(){cout<<"B()"<<endl;}
~B(){cout<<"~B()"<<endl;}
protected:
int b;
};
class A:virtual public D
{
public:
A(){cout<<"A()"<<endl;}
~A(){cout<<"~A()"<<endl;}
protected:
int a;
};
class C:public B, public A
{
public:
C(){cout<<"C()"<<endl;}
~C(){cout<<"~C()"<<endl;}
protected:
int c;
};
int main()
{
cout << "Hello World!" << endl;
C c; //D, B, A ,C
cout<<sizeof(c)<<endl;
return 0;
}
1931C++ 面向对象 C++ 类 & 对象
1930C++ 面向对象 C++ 类 & 对象
在类的外面,其实也可以用指针访问类内部的私有成员,例如:
#include <iostream>
using namespace std;
class a // 定义了类a
{
long a0; // 定义私有成员 a0
public:
a(long b)
{
a0=b;
}
void geta()
{
cout<<a0<<endl;
}
};
int main()
{
a b(5); // 定义对象b,并给 b 中的 a0 赋初值
long *p;
p=(long*)&b; // 令指针 p 指向 b 中前 4 个字节,在这里相当于指向 a0
b.geta(); // 用内部函数访问 a0
cout<<*p<<endl; // 在外部直接访问 a0
*p=8; // 在外部改变 a0 的值
b.geta(); // 输出改变后的结果
cout<<*p<<endl;
return 0;
}
1934C++ 重载运算符和重载函数
类重载、覆盖、重定义之间的区别:
重载指的是函数具有的不同的参数列表,而函数名相同的函数。重载要求参数列表必须不同,比如参数的类型不同、参数的个数不同、参数的顺序不同。如果仅仅是函数的返回值不同是没办法重载的,因为重载要求参数列表必须不同。(发生在同一个类里)
覆盖是存在类中,子类重写从基类继承过来的函数。被重写的函数不能是static的。必须是virtual的。但是函数名、返回值、参数列表都必须和基类相同(发生在基类和子类)
重定义也叫做隐藏,子类重新定义父类中有相同名称的非虚函数 ( 参数列表可以不同 ) 。(发生在基类和子类)
1933C++ 重载运算符和重载函数
1932C++ 继承
另外多继承(环状继承),A->D, B->D, C->(A,B),例如:
这个继承会使D创建两个对象,要解决上面问题就要用虚拟继承格式
格式:class 类名: virtual 继承方式 父类名
虚继承--(在创建对象的时候会创建一个虚表)在创建父类对象的时候
实例:
1931C++ 面向对象 C++ 类 & 对象
1930C++ 面向对象 C++ 类 & 对象
在类的外面,其实也可以用指针访问类内部的私有成员,例如:
需要注意的是,使用这种方法虽然可以用于基于类的多态原则的一些程序开发,但违反了类的封装原则,在使用指针的类中也极不安全,所以不建议使用。