C++-Review

Author Avatar
YZ 1月 06, 2018

C++程序设计语言的设计理念,演化历程,与C的关系

理念:强大的表述能力,高效灵活

历程:

1)Ole-Johan Dahl 提出OOP

2) Kristen Nygaard 发明Simula

3) Dennis Retchie & Ken Thompson 设计C语言

4)Bjarne Stroustrup 对C语言进行改进和补充,形成了C with class

5)Rick Mascitti 将其正式命名为C++

关系:

1)C++完全支持C语言成分,支持C的全部变成技巧

2)任何C程序可以被C++用基本相同的方法编写,并具备相同时间和空间开销

​3) C++扩充C,引入重载,内联函数,异常处理等功能,添加OOP的完全支持

影响表达式值的因素

操作符,操作数,优先级,结合性,求值次序,类型转换约定

Constructor

拷贝构造函数参数必须为const,以防传入一个const引用而报错;

成员初始化表:先于构造函数执行,按类数据成员声明次序

explicit抑制构造函数的隐式转换http://blog.csdn.net/KjfureOne/article/details/72830001


拷贝构造函数VS赋值函数

  1. 拷贝构造函数是构造函数,不返回值;生成一个全新的对象,函数调用之前对象是不存在的;
  2. 赋值函数需要返回一个对象自身的引用,以便赋值之后的操作;是对两个已有对象的操作。
1
A a; A b=a;//拷贝构造函数!!!因为b是新产生的对象
  1. 指针常量VS常量指针

    char greeting[] = “Hello”;


    常量指针(指向常量的指针)

    const int p 或 int const p两者是等价的

    const char *p2 = greeting; 指针可变,数据不变


    指针常量(指针本身是常量)

    int * const p = &a;

    char const p3 = greeting; 指针是常量,数据可变;必须在声明的同时进行初始化,不允许先声明一个指针常量然后赋值,和一般常量一样。**为中间划一条线,看const修饰谁就谁是常量**

C++绑定

默认静态绑定,即在编译时刻,根据引用或指向的对象类型来确定方法调用

虚函数采用动态绑定 书P234-235🌟

C++类提供的6+2个成员函数,如class Empty{ }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
默认构造函数 Empty( ) { }

析构函数 ~Empty( ) { }

拷贝构造函数 Empty(const Empty&);

赋值操作符重载 Empty& operator=(const Empty&);//const减少拷贝构造函数调用,提高效率

取地址操作符重载 Empty* operator&( );

带有const的取地址操作符重载 const Empty* operator&( ) const;

移动赋值操作符 Empty& operator=(Empty&&);

移动构造函数 Empty(Empty&&);

创建对象

JAVA中 Student stu1 = new Student();

1) 右边的new Student,在堆空间里创建一个Student类的对象;

2)末尾的()表示在对象创建后,立即调用Student类的构造函数,对刚生成的对象进行初始化;

3)左边的Student stu1创建一个Student类引用变量,类引用,用来指向某个对象的对象引用,即指向某个Student对象的内存地址;

4)=操作符使对象引用指向刚创建的Student对象

C++中

Student student(20);栈空间

Student *student = new Student (20) ; 堆内存空间

1
2
class c;//在栈上创建类对象,程序退出其作用域后自动调用类的析构函数;
class *c=new class;//在堆上创建对象,必须delete释放对象,否则会造成内存泄漏;

http://blog.csdn.net/jackystudio/article/details/11523353

虚函数

不要瞎用虚函数,要维护vptr,vtbl;

虚函数形参有默认值,则派生类形参不论有无默认值,当用指向派生类的基类指针调用派生类虚函数时就会被基类的默认值覆盖。

http://blog.csdn.net/bigzhao_25/article/details/52123803

关于为何非成员函数,静态成员函数,内联成员函数,构造函数,友元函数不能时虚函数?

http://blog.csdn.net/ta893115871/article/details/8194836

基类构造函数对虚函数采用静态绑定P235

1
2
3
4
5
6
class Shape{
public:
virtual void draw()const=0;
virtual void error(const string& msg);
int objectID()const;
}

纯虚函数【只给出函数声明而没有给出实现】:只有函数接口会被继承,子类必须继承函数接口,并且给出实现代码;

一般虚函数:函数的接口及缺省实现代码都会被继承,子类必须继承函数接口,可以继承缺省实现代码;

非虚函数:函数的接口和实现代码都会被继承,必须同时继承接口和实现代码。

成员初始化表

派生类的构造函数的初始化列表可以包含基类的构造函数、派生类成员的初始化,但是不能有基类成员的初始化!

http://blog.csdn.net/libaineu2004/article/details/19565229

C++程序设计应该遵守的原则

1) Use const whenever possible;

2) Guard against potential ambiguity;
3) Strive for exception-safe code;
4) Use destructor to prevent resource leaks;

5)尽量使用初始化列表而不是赋值。一个好的原则是,能使用初始化列表的时候尽量使用初始化列表

6)Never call virtual functions during construction or destruction

操作符重载

a++ VS ++a

a++:

1
2
const Counter operator ++ ( int ) { Counter temp = *this; value++; return temp; }
//右值返回临时对象

++a:

1
2
Counter& operator ++ ( ) { value++; return *this; }
//左值返回引用

赋值操作赋只能用成员函数重载;

http://blog.csdn.net/songshiMVP1/article/details/52166549

含有成员对象的初始化

P191: 当类定义中包含成员对象时,成员对象的拷贝初始化可由成员对象类的拷贝构造函数来实现;自定义的拷贝构造函数不会去调用成员对象的拷贝构造函数,必须要在拷贝构造函数的成员初始化表中显式指出。

如果在拷贝构造函数的成员初始化表中没有指出调用成员对象的拷贝构造函数,则表示调用成员对象的默认构造函数。

C++不能返回局部变量的地址

c++值传递,java引用传递

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
#include<iostream>
using namespace std;
class Rational{
private:
int n, d;
public:
Rational(int num = 0, int denom = 0){ n = num; d = denom; }
int getn(){ return n; }
int getd(){ return d; }
friend const Rational& operator *(const Rational& lhs, const Rational& rhs);
};
//1)👌
const Rational& operator *(const Rational& lhs, const Rational& rhs){
Rational *result=new Rational(lhs.n*rhs.n, lhs.d*rhs.d);
return *result;
}
int main(){
int h;
Rational a(1, 2);
Rational b(3, 5);
Rational c = a*b;
cout << c.getn() << " " << c.getd();
cin >> h;
}
//不能直接返回局部变量的地址;可以通过引用来传递值的拷贝?

//2)👌
const Rational operator *(const Rational& lhs, const Rational& rhs){
return Rational(lhs.n*rhs.n, lhs.d*rhs.d);
}

//3)👌
const Rational& operator *(const Rational& lhs, const Rational& rhs){
Rational result (lhs.n*rhs.n, lhs.d*rhs.d);
return result;
}

//4)❌
Rational* operator *(const Rational& lhs, const Rational& rhs){
Rational result (lhs.n*rhs.n, lhs.d*rhs.d);
return &result;
}

内联函数

作用:1)提高程序的可读性;2)提高程序的运行效率

危害:1)增大目标代码;2)病态的换页;3)降低指令快取装置的命中率

建议:用于使用频率高的小段代码

限制:非递归,由编译系统控制

宏VS内联函数

宏有时会出现重复计算;宏只是简单的文字替换,不进行参数类型检查和转换;不利于一些工具对程序的处理,如调试程序交叉定位;

引用VS指针

引用:直接访问,与被引用变量共享内存,实参是变量

指针:间接访问,有自己的内存空间,实参是变量地址

1) 引用是采用直接访问形式,指针则采用间接访问形式——效率高;

2) 引用与被引用变量共享内存,而指针有自己的内存空间——内存占用少;

3) 在作为函数参数类型时,引用类型参数的实参是一个变量,而指针类型参数的实参是一个变量的地址——代码可读性好;

4) 引用类型一旦定义后不能改变,而指针变量定义后可以指向其他同类型的变量——安全。

静态成员

C++规定const静态类成员可以直接初始化,其他非const的静态类成员需要在类声明以外初始化

1
2
int A::n(9);
vector<int> A::buf(100);

类的对象作为函数参数

可以采用值传递或地址传递;

调用拷贝构造函数的情形:

1)一个对象作为函数参数,以值传递的方式传入函数体;

2)一个对象作为函数返回值,以值传递的方式从函数返回;

3)一个对象用于给另外一个对象进行初始化(赋值初始化)。

http://www.cnblogs.com/renyuan/archive/2012/12/29/2839230.html

P247例题,基类派生类作为函数参数

1
2
3
4
5
6
7
8
void func1(A a){
a.f();a.g();a.h();
}
//以类对象作为参数值传递,首先调用拷贝构造函数;都是调A。。。
void func2(A &a){
a.f();a.g();a.h();
}
//引用传递,不调用copy,传个地址而已;虚函数有用咯😄

基类、派生类拷贝构造函数调用&赋值操作符⚠️

对于拷贝构造函数,派生类的隐式拷贝构造函数将会调用基类的拷贝构造函数;

派生类自定义的拷贝构造函数在默认情况下调用基类的默认构造函数;但是可以在成员初始化表中指出调用基类的拷贝构造函数。

在派生类的赋值操作符重载函数的实现中需要显式地调用基类的赋值操作符来实现对基类成员的赋值;

1
2
3
4
5
6
7
8
9
10
11
class A{...};
class B:public A{
......
public:
B& operator=(const B&b){
if(&b==this) return *this;
*(A*)this=b;
......
return *this;
}
};

对基类成员的赋值操作也可以写成:

1
this->A::operator=(b);

模板

1
2
3
4
5
6
7
8
9
template <class T> class A{
static int x;
T y;
......
};
template <class T> int A<T> ::x=0;
......
A<int> a1,a2;
A<double> a3,a4;
1
2
3
4
5
6
7
8
9
template <class T1,class T2> 
class A{
public:
bool exec();
};
template <class T1,class T2>
bool A<T1,T2>::exec(){
......
}

new VS malloc

1)new自动计算所需分配的内存空间大小,而malloc需要显式指出

2)new自动返回相应类型的指针,而malloc要强制类型转换

3)如果创建的是动态对象,new会去调用相应对象类的构造函数,而malloc则不会

函数指针

1
double (*fp) (int);

fp可以指向返回类型为double,参数类型为int的任何函数;【多态】

规则引用声明符&&

可以利用移动语义,将资源(如动态分配的内存)从一个对象转移到另一个对象;移动语义可以使资源能够从无法在程序中的其他位置引用的临时对象转移

C++考完啦~~~撒花🎆

虚拟继承没复习到💔(多继承还看过一遍书,没注意。。)

谁说取地址不能虚函数的。。

为什么模板放在头文件里

读程序写答案不知道它能不能编译啊

一个字符串给它每三位加逗号,pmx说用指针,队列可以么。。