面向对象编程(一)基础知识
类不是实体,对象是实体
成员变量(filed)属于对象
成员函数(member function)属于类
初始化列表
列表初始化(initialize list)仅对成员变量初始化。
在构造函数里对成员变量初始化则为先初始化(默认)后赋值,故所有成员变量必须要有默认的初始化方法(成员变量包含其他类但该类没有默认构造函数则会报错)。构造函数无法主动调用。
尽量使用列表初始化
1 2 3 4 5 6
| class A{ public: int a; A(int i):a(i){}; };
|
拷贝构造和拷贝赋值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| class Test { public: Test() : ptr(0) { ptr = new char[1]; ptr[0] = '\0'; cout << "call Test()" << endl; }; Test(const char *c_ptr) { if (c_ptr) { ptr = new char[strlen(c_ptr) + 1]; } else { ptr = new char[1]; ptr[0] = '\0'; } cout << "call Test(const char *c_ptr)" << endl; }; Test(Test &test) { ptr = new char[strlen(test.ptr) + 1]; strcpy(ptr, test.ptr); cout << "call Test(Test &test)" << endl; }; Test &operator=(Test &test) { if (this == &test) return *this; delete[] ptr; ptr = new char[strlen(test.ptr) + 1]; strcpy(ptr, test.ptr); cout << "call copy operator=" << endl; return *this; }
private: char *ptr; };
int main() { Test test; Test test1("123"); Test test2 = test1; Test test3(test1); test3 = test2; }
|
拷贝构造
通过类的其他对象初始化当前对象(有默认拷贝构造方法,成员对成员的拷贝,可能发生对象的嵌套拷贝)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| void roster(Person){}; Person child("Ruby"); roster(child);
Person baby_a("Fred"); Person baby_b = baby_a; Person baby_c(baby_a);
Person captain(){ Person player("George"); return player; }
|
T::T(const T&)
建议每个类提供默认构造函数,拷贝构造函数,虚函数
继承
访问属性
访问限制符\访问位置 |
当前类 |
子类 |
类外 |
public |
可以 |
可以 |
可以 |
protected |
可以 |
可以 |
不可以 |
private |
可以 |
不可以 |
不可以 |
若子类中含有与父类同名函数(函数名相同,参数列表个数和类型),父类的函数会被隐藏。(仅C++如此)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class A{ public: int i; A(int a):i(a){}; void print(){cout<<"A::print()"<<endl;}; void print(int a){cout<<"A::print(int i)"<<endl;}; };
class B:public A{ public: B(int a):A(a){}; void print(){cout<<"B::print()"<<endl;}; };
int main(){ B b(4); b.print(2); }
|
友元
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数称为它的友元
1 2 3 4 5 6 7
| class Sales_data{ friend Sales_data add(const Sales_data&, const Sales_data&); public: private: };
|
一般来说,最好在类定义开始货结束前的集中位置声明友元
友元的声明只指定了访问的权限,而非一个通常意义上的函数声明。如果我们希望类的用户能够调用某个友元函数,那么就必须在友元声明外再专门对函数进行一次声明
相同类的对象互为友元
虚函数
向上造型(upcasting)指将派生类的引用或指针转化为父类的引用或指针
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| class Base { public: Base() : i(0) {} void print() { cout << "Base print" << endl; }
private: int i; };
class Derived : public Base { public: void print() { cout << "Derived print" << endl; } };
void test_print(Base &a) { a.print(); }
int main() { Base test; Derived test2; test_print(test2); return 0; }
|
虚函数:使派生类各自定义适合自己版本的函数,当使用基类的引用(或指针)调用一个虚函数时将发生动态绑定(父类加上virtual即生效,但最好子父类都加上virtual)
静态绑定:编译时确定调用的函数
动态绑定:运行时确定调用的函数
如果派生类没有覆盖基类的虚函数,则派生类会直接继承基类中的版本
对象增加vptr,指向当前对象的类的vtable(属于类,保存存储虚函数的地址)
虚函数运行方式为访问vptr—访问vtable—访问函数指针—访问函数
如果有一个虚函数,则需将析构函数设为虚函数,以处理新增变量
C++默认静态绑定
派生类虚函数的形参类型个数,返回值类型必须和基类一致,否则为重载(除非返回类型时类本身的指针或引用)
其他
private针对类而非对象,可访问另一对象中的private成员