二义性:
- 多继承的派生类中,多个基类有同名数据成员或函数成员。当使用派生类对象访问这些成员时,如果不进行一些访问控制权限的处理就会出现二义性。
- 数据成员的二义性&&函数成员的二义性——名为A/func的成员有多个副本
#include<iostream>
using namespace std;
class Base0{
public:
int A;
void func(){cout << "Base0 func()" << endl;}
};
class Base1{
public:
int A;
void func(){cout << "Base1 func()" << endl;}
};
class Derived:public Base0,public Base1{
public:
};
int main(){
Derived d;
//d.A = 0;——数据成员的二义性
//d.func();
}
- 解决:通过作用域分隔符限制:
int main(){
Derived d;
//d.A = 0;
d.Base0::A = 0;
d.Base1::A = 1;
//d.func();
d.Base0::func();
d.Base1::func();
}
- 函数成员的二义性——可能用同一段代码;没有多个副本,但仍需要限制作用域
#include<iostream>
using namespace std;
class Base0{
public:
int A;
void func(){cout << "Base0 func()" << endl;}
};
class Base1:public Base0{
};
class Base2:public Base0{
};
class Derived:public Base1,public Base2{
};
int main(){
Derived d;
//函数成员的二义性,d.func();
d.Base1::func();
}
reason:Base1与Base2都是Base0的派生类,而func()是非静态成员函数,func的调用依赖于this指针(目的对象),因此要声明是Base0的哪一个派生类的func()函数
引申
-
静态成员的继承——基类和其派生类共享基类的静态成员变量内存
这也就是为什么我们在讨论虚继承的时候,不讨论静态成员;可以把静态成员看成全局函数,也就不会存在二义性的问题。
#include<iostream>
using namespace std;
class Base0{
public:
int A;
static void func(){cout << "Base0 func()" << endl;}
};
class Base1:public Base0{
};
class Base2:public Base0{
};
class Derived:public Base1,public Base2{
};
int main(){
Derived d;
//d.A = 0;——数据成员的二义性
Base0::func();
d.Base1::func();
//注意,静态成员没有二义性
d.func();
//以上调用的都是同一个函数,同一块内存
}
虚函数——多态的基础
为了解决多继承二义性问题(这里指的是,减小开销(不要多个副本,而是虚继承的类族共同维护一个副本),不通过使用作用域分隔符限制)
#include<iostream>
using namespace std;
class Base0{
public:
Base0(int a):A(a){cout << "Base0 construct func" << endl;}
int A;
void func(){cout << "Base0 func()" << endl;}
};
class Base1:virtual public Base0{
public:
Base1(int a):Base0(a){cout << "Base1 construct func" << endl;}
};
class Base2:virtual public Base0{
public:
Base2(int a):Base0(a){cout << "Base2 construct func" << endl;}
};
//注意:Derived也是Base0虚继承类族里的类,Base0也是Derived的基类,也需要对其初始化
class Derived:public Base1,public Base2{
public:
Derived(int i):Base1(i),Base0(i),Base2(i)
{cout << "Derived construct func " << endl;}
};
int main(){
Derived d(3);
d.func();
//调用默认复制构造函数,类型兼容规则指出,可以用派生类的对象初始化基类的对象
Base1 b = d;
b.func();
}
多态
运算符重载的各种形式
- 注意单目运算符的重载
#include<iostream>
using namespace std;
class Complex{
int a,b;
public:
Complex(int x,int y):a(x),b(y){};
//运算符重载为友元函数
friend Complex operator*(Complex x,Complex y);
//运算符重载为成员函数,在类内定义
void operator+(Complex x){
a += x.a;
b += x.b;
}
void operator-(Complex x);
//重载单目运算符——前置
Complex& operator++();
Complex operator++(int);
const int Geta(){return a;}
const int Getb(){return b;}
};
//运算符重载为成员函数,在类外定义
void Complex::operator-(Complex x){
a -= x.a;
b -= x.b;
}
//运算符重载为(友元)非成员函数
Complex operator*(Complex x,Complex y){
return Complex(x.a*y.a-x.b*y.b,x.a*y.b+x.b*y.a);
}
//运算符重载为非成员函数
ostream& operator<<(ostream& out,Complex x){
cout << x.Geta() << endl << x.Getb()<< endl;
return out;
}
//重载单目运算符——前置
Complex& Complex::operator++(){
this->a++;
return *this;
}
//后置(int参数用来区分前置or后置,reason返回的是原来的this,也就是说,原来的*this(对象)是这个重载函数的局部变量,运行结束之后,消失。所以要返回对象)
Complex Complex::operator++(int){
Complex old = *this;
this->a++;
return old;
}
int main(){
Complex x(3,5);
x+x;
x = x*x;
Complex y(1,2);
cout << y << x;
cout << y++;
cout << y;
cout <<++y;
}
虚函数
#include<iostream>
using namespace std;
class Base0{
public:
//virtual void display(){cout << "Base0 display" << endl;}
void display(){cout << "Base0 display" << endl;}
};
class Base1:public Base0{
public:
//virtual void display(){cout << "Base1 display" << endl;}
void display(){cout << "Base1 display" << endl;}
};
class Derived:public Base1{
//virtual void display(){cout << "Derived display" << endl;}
void display(){cout << "Derived display" << endl;}
};
void func(Base0& ptr){
ptr.display();
}
int main(){
Derived d;
func(d);
Base0 b0;
func(b0);
Base1 b1;
func(b1);
}
-
运行结果
不声明虚函数
Base0 display
Base0 display
Base0 display声明虚函数(采用注释的方法)
Derived display
Base0 display
Base1 display
纯虚函数与抽象类
#include<iostream>
using namespace std;
class Base1{
public:
//纯虚函数的定义
virtual void display() const = 0;
};
class Base2:public Base1{
public:
virtual void display()const{cout << "Base2 display" << endl;}
};
class Derived:public Base2{
public:
virtual void display()const{cout << "Derived display" << endl;}
};
void f(Base1& ptr){
ptr.display();
}
int main(){
Derived d;
f(d);
//Base1 B1;___报错,抽象类不能实例化
//f(B1);
Base2 B2;
f(B2);
}
- 运行结果
Derived display
Base2 dispaly