继承 访问控制 使用:
进行继承,有三种继承的方式public
,protected
,private
,被继承的类叫做基类 ,继承基类的类叫做派生类
public
、protected
和 private
是三种访问控制修饰符 ,用于控制成员在类的内部和外部的可见性和可访问性,public在类的内外都可以访问,protected在类的外部不可访问,在子类中可以直接访问,但子类中不能通过对象名对protected进行访问,private在子类中也不可访问
public
:基类的public成员在派生类中仍为public,积累的protected成员在派生类中仍是protected,基类的private成员为private
protected
:基类的public成员在派生类中变成protected,积累的protected成员在派生类中仍为protected,积累的private成员为private
private
:基类的public和protected成员在派生类中都变成private
继承中的构造函数和析构函数 创建子类会先调用父类的构造函数
子类不能继承父类的构造函数,但可以显式调用父类的构造函数,如果没有调用基类的构造函数,基类的默认构造函数会在子类的构造函数之前自动调用,如果基类没有默认构造函数,子类必须通过:BaseClass()
的方式显示调用基类的构造函数
销毁子类会先调用子类的析构函数
当对象被销毁时,子类的析构函数会首先被调用,然后基类的析构函数会被调用,析构函数的调用顺序和构造函数的调用顺序相反
多态和虚函数 通过使用虚函数(virtual) ,可以在基类中定义一个接口,并在派生类中重写该接口的实现,这样,基类指针或引用可以指向派生类对象,并调用派生类的重写方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Base {public : virtual void show () { std::cout << "Base class show function" << std::endl; } }; class Derived : public Base {public : void show () override { std::cout << "Derived class show function" << std::endl; } }; int main () { Base* basePtr = new Derived (); basePtr->show (); delete basePtr; return 0 ; }
对于虚函数,在基类中有了实现,那么子类不一定必须进行重写,如果没有重写,就会调用父类中的虚函数。而基类中没有实现的虚函数叫做纯虚函数 ,使用=0
表示该函数时虚函数,纯虚函数强制派生类必须提供该函数的实现,含有纯虚函数的类时抽象类,无法实例化
多重继承 c++支持多重继承,即一个类可以从多个基类继承。
在多重继承中,如果基类中有相同名称的函数,派生类需要显示指定调用的哪一个基类的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Base1 {public : void show () { std::cout << "Base1 class show function" << std::endl; } }; class Base2 {public : void show () { std::cout << "Base2 class show function" << std::endl; } }; class Derived : public Base1, public Base2 {}; int main () { Derived obj; obj.Base1::show (); obj.Base2::show (); return 0 ; }
虚继承 当多重继承中多个基类继承自同一个祖先类时,可能会发生“菱形继承 ”——祖先类的成员在派生类中出现多次,为了解决这个问题,C++提供了虚继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class A {public : int value; }; class B : virtual public A {}; class C : virtual public A {}; class D : public B, public C {}; int main () { D obj; obj.value = 10 ; return 0 ; }
操作符重载 所有重载的操作符本质上都是一个函数,操作符对应的操作子是该操作符函数的参数。任意一个操作符都能被重载为自由函数或成员函数。定义重载函数时要保证每一个操作子都有对应的参数位置,
我们可以在类的内部声明友元函数,然后在类的外部实现友元函数,这样能更加方便的对类内的成员进行访问。如果对同一个操作符,在多个类上进行不同的操作符重载,那么每个被重载的类都有自己对应的操作符
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 #include <iostream> #include <string> using namespace std;class Person {private : string name_; int age_; public : Person (const string& name, int age) : name_ (name), age_ (age) {} friend ostream& operator <<(ostream& os, const Person& person) { os << "Person(Name: " << person.name_ << ", Age: " << person.age_ << ")" ; return os; } }; class Car {private : string brand_; int year_; public : Car (const string& brand, int year) : brand_ (brand), year_ (year) {} friend ostream& operator <<(ostream& os, const Car& car) { os << "Car(Brand: " << car.brand_ << ", Year: " << car.year_ << ")" ; return os; } }; int main () { Person p1 ("John Doe" , 30 ) ; Car c1 ("Toyota" , 2020 ) ; cout << p1 << endl; cout << c1 << endl; return 0 ; }
流操作符返回值为流是为了实现链式操作。
隐式类型转换 当为用户自定义的类型进行操作符重载时,如果要对基本类型进行操作,要么对一个操作符进行多次重载,要么显式地写出转换
除了C++的standard conversion,C++还允许用户自定义隐式转换规则,只要有对应地user-defined conversion
user-defined conversion 有两种:
转换构造函数 (converting constructor)
用户定义的转换函数 (user-defined conversion constructor)
转换构造函数 是所有构造函数的一种性质,凡是没有explicit
说明符的构造函数都是转换构造函数
例如我们定义以下
1 2 3 4 5 6 7 8 class complex { public : complex (doubole d); friend complex operator +(complex c,complex d); } complex a; double d;complex z = a+d;
那么在执行complex z = a+d;
的时候,d
会进行隐式类型转换变为complex
,但是如果operator+
是成员函数,在参数传递的时候就会失去对称性,所以一般将=
操作符设置为成员函数,=
作为成员函数重载还能保证第一个参数不会被改变。
如果构造函数被explicit
修饰,那么这个构造函数就不是converting constructor,不能用作隐式类型转换,只能用作显式类型转换
用户定义的转换函数
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 class Complex { double r, i; public : Complex (double r) : r (r), i (0 ) {}; Complex (double r, double i) : r (r), i (i) {}; operator string () const { cout << "operator string" << endl; return to_string (r) + " + " + to_string (i) + 'i' ; } explicit operator double () const { cout << "operator double" << endl; return r; } explicit operator bool () const { cout << "operator bool" << endl; return r != 0 || i != 0 ; } }; void foo (double ) ;int main () { Complex c = 3 ; string str = c; foo (double (c)); foo ((double )c); if (c) { cout << str; } return 0 ; }
string()
,explicit double()
,explicit bool()
都是用户定义的转换函数,其中double
加上了explicit
只能显式调用,bool
虽然加上了explicit
,但是在上下文包括if
,while
,for
的条件语句!
,||
,&&
,以及三元操作符?:
时,即使加上explicit
,bool()
的隐式转换也会执行
线程