當多態遇見對象數組會發生什麼?
#include <cstdlib>
#include <iostream>
using namespace std;
//4字節VPTR + 4字節的int i = 8字節
class Parent
{
protected:
int i;
public:
virtual void f()
{
cout<<"Parent::f"<<endl;
}
};
//4字節VPTR + 4字節的int i + 4字節的int j = 12字節
class Child : public Parent
{
protected:
int j;
public:
Child(int i, int j)
{
this->i = i;
this->j = j;
}
void f()
{
cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
}
};
int main(int argc, char *argv[])
{
Parent* p = NULL;
Child* c = NULL;
Child ca[3] = {Child(1, 2), Child(3, 4), Child(5, 6)};
cout<<"sizeof(Parent) = "<<sizeof(Parent)<<endl;
cout<<"sizeof(Child) = "<<sizeof(Child)<<endl;
p = ca;
c = ca;
cout<<hex<<&ca[0]<<endl;
cout<<hex<<&ca[1]<<endl;
cout<<hex<<p<<endl;
cout<<hex<<p+1<<endl;
p->f();
c->f();
p++;
c++;
//p->f();//Error
c->f();
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
編譯運行結果如下:
不要將多態應用於數組
1. 指針運算是通過指針的類型進行的,即是編譯器編譯的時候決定的;
2. 多態通過虛函數表實現的,是程序運行的時候決定的;
爲什麼沒有講解多重繼承?
C++在語法上直接支持多重繼承
#include <cstdlib>
#include <iostream>
using namespace std;
class P1
{
protected:
int i;
};
class P2
{
protected:
int j;
};
class Child : public P1,public P2
{
protected:
int j;
public:
Child(int i, int j)
{
this->i = i;
this->j = j;
}
void printf()
{
cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
}
};
int main(int argc, char *argv[])
{
Child c(1, 2);
c.printf();
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
編譯運行結果如下:
被實際開發經驗拋棄的多繼承
1. 工程開發中真正意義上的多繼承是幾乎不被使用的;
2. 多重繼承帶來的代碼複雜性遠多於其帶來的便利;
3. 多重繼承對代碼維護性上的影響是災難性的;
4. 在設計方法上,任何多繼承都可以用單繼承代替;
#include <cstdlib>
#include <iostream>
using namespace std;
class Object
{
protected:
int d;
public:
void f()
{
cout<<"Object::f"<<endl;
}
};
class P1 : public Object
{
protected:
int i;
};
class P2 : public Object
{
protected:
int j;
};
class Child : public P1, public P2
{
public:
Child(int i, int j)
{
//this->d = 0; //Error 不知道d是P1還是P2的,存在二義性
this->i = i;
this->j = j;
}
void print()
{
cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
}
};
int main(int argc, char *argv[])
{
Child c(1, 2);
c.print();
//c.f(); //Error 不知道f是P1還是P2的,存在二義性
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
在只有單繼承的系統中,類之間的繼承關係爲一顆樹。在引入多重繼承的系統中,類之間的繼承關係呈現爲一張圖。
C++中對多繼承二義性的解決方案
虛繼承:
爲了解決從不同途徑繼承來的同名數據成員造成的二義性問題,可以將共同基類設置爲虛基類。這時從不同的路徑繼承過來的同名數據成員在內存中就只有一個拷貝。
#include <cstdlib>
#include <iostream>
using namespace std;
class Object
{
protected:
int d;
public:
void f()
{
cout<<"Object::f"<<endl;
}
};
class P1 : virtual public Object
{
protected:
int i;
};
class P2 : virtual public Object
{
protected:
int j;
};
class Child : public P1, public P2
{
public:
Child(int i, int j)
{
this->d = 0;
this->i = i;
this->j = j;
}
void print()
{
cout<<"i = "<<i<<" "<<"j = "<<j<<endl;
}
};
int main(int argc, char *argv[])
{
Child c(1, 2);
c.print();
c.f();
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
編譯運行結果如下:
C++是否有Java中接口的概念?
絕大多數面嚮對象語言都不支持多繼承;
絕大多數面嚮對象語言都支持接口的概念;
C++中沒有接口的概念;
C++中可以使用純虛函數實現接口;
#include <cstdlib>
#include <iostream>
using namespace std;
class Interface1
{
public:
virtual void print() = 0;
virtual int add(int i, int j) = 0;
};
struct Interface2
{
virtual int add(int i, int j) = 0;
virtual int minus(int i, int j) = 0;
};
class Child : public Interface1, public Interface2
{
public:
void print()
{
cout<<"Child::print"<<endl;
}
int add(int i, int j)
{
return i + j;
}
int minus(int i, int j)
{
return i - j;
}
};
int main(int argc, char *argv[])
{
Child c;
c.print();
cout<<c.add(3, 5)<<endl;
cout<<c.minus(4, 6)<<endl;
Interface1* i1 = &c;
Interface2* i2 = &c;
cout<<i1->add(7, 8)<<endl;
cout<<i2->add(7, 8)<<endl;
cout << "Press the enter key to continue ...";
cin.get();
return EXIT_SUCCESS;
}
編譯運行結果如下: