C++_primer_2面向对象

C++ 进阶(面向对象)

如果既可以通过初始化,也可以通过赋值来设置对象的值,则应采用初始化方式.通常这种方式的效率更高.

this指针和const联合

如果方法需要引用整个调用对象,则可以使用表达式*this.在函数的括号后面使用const限定符将this限定为const,这样将不能使用this来修改对象的值. this指针指向用来调用成员函数的对象(this被作为隐藏参数传递给方法)


友元函数

使用非成员函数可以按所需的顺序获得操作数,但引发了一个新问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问.特殊的成员函数可以访问类的私有成员--友元函数

既不属于类的私有成员函数,又可以访问类的私有成员变量.


构造函数在重载中的使用

在类的函数运算符重载中

Vector Vector::operator+(const Vector & b) const
{
    return Vector(x + b.x,y + b.y);
}

代码中将新的x分量和y分量传递给Vector构造函数,而后者将使用这些值来创建无名的新对象,并返回该对象的副本.这确保新的Vector对象是根据构造函数制定的标准规则创建的.


自动转换关闭

c++中 利用explicit用于关闭将构造函数用作自动类型转换函数的特性. 构造函数用于某种类型到类类型的转换,如果要进行相反的转换,必须使用c++运算符函数--转换函数 double host = double(wolfe);


类中的运算符重载

大多数运算符都可以通过成员或非成员函数进行重载,但下面的运算符只能通过成员函数进行重载

=  赋值运算符
() 函数调用运算符
[] 下标运算符
-> 通过指针访问类成员的运算符

构造函数使用new时应该注意的问题

使用new初始化对象的指针成员时,正确的做法:

  1. 如果构造函数中使用new来初始化指针成员,则应在析构函数中使用delete.
  2. new和delete必须相互兼容,成对出现.
  3. 多个构造函数时,为了与delete对应,必须以相同的方式使用new.

返回对象的说明

当成员函数或独立的函数返回对象时,可以返回指向对象的引用/指向对象的const引用或const对象.四种情况:引用和非引用,const和非const

指针和对象小结

使用对象指针,需要注意的问题

  1. 使用常规表示法来声明指向对象的指针

String * glamour;

  1. 可以将指针初始化为指向已有的对象

String * first = &sayings[0];

  1. 可以使用new来初始化指针,这将创建一个新的对象

String * favorite = new String(sayings[choice]);

  1. 对类使用new将调用相应的类构造函数来初始化新创建的对象

String * gleep = new String;

String * glop = new String("my my my")

通过不同的参数,调用不同的构造函数.

delete可以与常规new运算符配合使用,但不能与定位new运算符配合使用.

定位new运算时,需要考虑buffer位置,进行移位操作.

结束后,需要自行调用析构函数,完成析构操作.

 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
55
56
57
58
59
60
61
62
//
// Created by 博凯 Chen on 2022/3/21.
//

#include <iostream>
#include <string>
#include <new>

using namespace std;
const int BUF= 512;
class JustTesting
{
private:
    string words;
    int number;
public:
    JustTesting(const string &s = "JustTesting",int n = 0)
    {
        words = s;
        number = n;
        cout<<words<<"constructed\n";
    }
    ~JustTesting(){
        cout<<words<<"destoryed\n";
    };
    void SHow() const{cout<<words<<","<<number<<endl;}
};

int main(void)
{
    char *buffer = new char[BUF];
    JustTesting *pc1,*pc2;

    pc1 = new(buffer) JustTesting;
    pc2 = new JustTesting("Heap1",20);

    cout<<"buffer: "<<(void *)buffer<<endl;
    cout<<"heap: "<<pc2<<endl;

    cout<<pc1<<":";
    pc1->SHow();
    cout<<pc2<<":";
    pc2->SHow();


    JustTesting *pc3,*pc4;
    pc3 = new(buffer+sizeof(JustTesting)) JustTesting("Bad Idea");
    pc4 = new JustTesting("Heap2",10);

    cout<<pc3<<": ";
    pc3->SHow();
    cout<<pc4<<": ";
    pc4->SHow();

    delete pc2;
    delete pc4;

    pc3->~JustTesting();
    pc1->~JustTesting();

    return 0;
}

输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
/Users/bokaichen/c++_primer/placenew/cmake-build-debug/placenew
JustTestingconstructed
Heap1constructed
buffer: 0x7f97a8704290
heap: 0x60000377d140
0x7f97a8704290:JustTesting,0
0x60000377d140:Heap1,20
Bad Ideaconstructed
Heap2constructed
0x7f97a87042b0: Bad Idea,0
0x60000377d160: Heap2,10
Heap1destoryed
Heap2destoryed
Bad Ideadestoryed
JustTestingdestoryed

Process finished with exit code 0


成员初始化列表

对于const类成员,必须使用成员初始化列表,而且必须在构造函数中使用.对于被声明为引用的类成员,也必须使用这种语法.

1
2
3
4
5
6
7
class Agency{...};
class Agent
{
  private:
  	Agency & belong;
};
Agent::Agent (Agency & a):belong(a){...}

不能将成员初始化列表用于构造函数之外的其他类方法.

  • 这种格式只嗯呢该用于构造函数
  • 必须用这种格式来初始化非静态const数据成员
  • 必须用这种格式来初始化引用数据成员

访问基类的私有部分

基类的私有部分也将成为派生类的一部分,但是只能通过基类的公有和保护防范访问.

派生类不能直接访问基类的私有成员,必须通过基类方法进行访问.


virtual的使用

如果方法是通过引用或指针而不是对象调用的,又没有使用关键字virtual,程序将根据引用类型或指针类型选择方法;如果使用了virtual,程序将根据引用或指针指向的对象的类型来选择方法.

如果要在派生类中重新定义基类的方法,通常应将基类方法声明为虚的.这样,程序将根据对象类型而不是引用或指针的类型来选择方法版本.为基类声明一个虚析构函数也是一种惯例.

virtual double Area( ) const = 0;

纯虚函数 使用=0定义类是抽象类,在派生类中可以实现也可以不实现.


静态联编和动态联编

联编(binding)


虚基类

虚基类使得从多个类派生出的对象只继承一个基类对象.

eg:通过在类声明中使用关键字virtual,可以使Worker被用作Singer和Waiter的虚基类(virtual和public的次序无关紧要):

1
2
3
4
class Singer:virtual public Worker{...};
class Waiter:public virtual Worker{...};
#然后可以将SingingWaiter类定义为:
class SingingWaiter:public Singer,public Waiter{...};

此时,SingingWaiter对象将只包含Worker对象的一个副本.继承的Singer和Waiter对象共享一个Worker对象.

c++在基类是虚的时候,禁止信息通过中间类自动传递给基类.


友元类

友元类的所有方法都可以访问原始类的私有成员和保护成员.

两个类之间没有派生和继承关系,并且一个类需要访问另一个类中的保护/私有成员数据时,用友元类来定义(电视机和遥控器的关系).

为了使编译器在一开始知道Tv和Remote的类型,当使用友元类时,需要使用前向声明.

友元类的方法采用内联函数进行编写.


智能指针

Auto_ptr 系统不推荐使用(行为不确定)

shared_ptr 如果程序要使用多个指向同一个对象的指针时使用.

unique_ptr 如果程序不需要多个指向同一个对象的指针


updatedupdated2022-03-282022-03-28