c++ primer 学习笔记(2): 函数 function

类:简单来说就是数据和它的操作的一种封装,内部提供接口函数

1.“ 定义 ”在类内部的函数是隐式inline的。

2.this

成员函数通过一个名为this的额外的隐式参数来访问调用它的那个对象。用请求该函数的对象的地址来初始化this。

仍何对类成员的访问都被看作this的隐式引用。

[cpp] view
plain
 copy

  1. std::string isbn( ) { return bookNo; }
  2. std::string isbn( ) { return this->bookNo; }
  3. //二者是等价的

this是一个常量指针,不允许改变this中保存的地址

3.const 成员函数

this是一个指向类类型非常量版本的常量指针。

[cpp] view
plain
 copy

  1. Sales_data  * const this

所以我们不能把this绑定到一个常量对象上。所以我们不能在一个常量对象上调用普通的成员函数。

const 常量成员函数:C++允许把const关键字写在函数的参数列表后面表示this是一个指向常量对象的指针。

[cpp] view
plain
 copy

  1. #include <iostream>
  2. #include <string>
  3. using namespace std;
  4. class Sales_data
  5. {
  6. //isbn()函数后面添加const,实际上是修饰this指针,表示
  7. //this是一个指向常量的指针。所以isbn()函数内不会修改
  8. //this所指向的内容,当然this可以省略.
  9. std::string isbn() const { return this->bookNo; }
  10. private:
  11. std::string bookNo;       //图书编号
  12. unsigned units_sold = 0;  //销售单价
  13. double revenue = 0.0;     //总销售额
  14. };

!常量对象,以及常量对象的指针或者引用都只能调用常量成员函数。

一个const 成员函数如果以引用的方式返回*this,那么它的返回类型是常量引用。

来分析一个问题,static成员在常量成员函数中能改变吗?

答案是可以的。

static成员存在于内存中的静态区,和类的普通成员存在的位置不一样,其次来看看函数参数列表后面加上const的情况

在普通成员函数中,this指针是一个常量指针,我们访问变量等都是通过this指针访问,一般省略,this指针形式类似   类型 * const this

当我们变成常量成员函数的时候,this指针变成了  const  类型 * const  this ,所以我们不能修改常量成员函数里的变量,因为this是指向常量的常量指针。

但是static变量和普通变量却不再一块区域存储,那么当然不受this指针的控制,!所以在常量成员函数里面可以修改static成员变量。

4.定义类相关的非成员函数

属于类的接口组成部分,但不属于类的本身。

I/O类不能被拷贝。

执行输出的函数应该减少对格式的控制,这样可以确保由用户代码来决定是否换行。

5.构造函数 :构造函数的唯一目的就是为成员赋初值。

定义:类通过一个或几个特殊的成员函数来控制其对象初始化的过程。

只要对象被创建,就会执行构造函数。

默认构造函数:类通过一个特殊构造函数来控制默认初始化过程。默认构造函数无需实参

合成默认构造函数:我们没有定义构造函数时,编译器为我们定义的构造函数。

[cpp] view
plain
 copy

  1. class Sales_item
  2. {
  3. Sales_item( ) = default;
  4. Sales_item( const std::string &s) : bookNo(s) { }      //若不是引用的话,可以std::string s,是&必须加const,保证不会改变s。
  5. Sales_item( const std::string &s, unsigned n, double p) : bookNo(s), units_sold(n), revenue(p) { }
  6. private:
  7. std::string bookNo;
  8. unsigned units_sold;
  9. double revenue;
  10. }
  11. // Sales_item( ) = default;    c++11标准中,如果我们需要默认的行为,那么可以通过早参数列表后面写上 = default 来要求编译器生成构造函数。

c++ 11 类内初始值

[cpp] view
plain
 copy

  1. class c
  2. {
  3. c( ): { }
  4. private:
  5. int i = 10;   //类内初始值
  6. }

通常情况下,构造函数使用类内初始值不失为一种好的选择,因为只要这样的初始值存在我们就能确保为成员赋予了一个正确的值。

类内初始值只在没有任何构造函数的情况下才起作用

在类外部定义构造函数

[cpp] view
plain
 copy

  1. Sales_data::Sales_data( std::istream &is)
  2. {
  3. read(is, *this);  //read函数从is中读取一条信息存到this中去。
  4. }

接下来来分析一个实例类

[cpp] view
plain
 copy

  1. class Sales_data
  2. {
  3. public:
  4. Sales_data() = default;
  5. Sales_data(std::string s):bookNo(s), units_sold(0), revenue(0.0) { }
  6. Sales_data(std::string s, unsigned n, double p): bookNo(s), units_sold(n), revenue(p) { }
  7. std::string isbn() const { return bookNo; }
  8. Sales_data& combine(const Sales_data &rhs);
  9. double avg_price() const { return revenue/units_sold; }
  10. Sales_data& operator=(const Sales_data &rhs);
  11. friend ostream& print(ostream& os, const Sales_data& item);
  12. friend istream& read(istream& is, Sales_data& item);
  13. friend Sales_data add(const Sales_data&item1, const Sales_data&item2);
  14. private:
  15. std::string bookNo = "w";   //编号
  16. unsigned units_sold = 0;    //销售数量
  17. double revenue = 0;         //总销售额
  18. //double price;         //单价
  19. };
  20. int main()
  21. {
  22. Sales_data item1;
  23. Sales_data item2("wangweihao");
  24. Sales_data item3("wangweihao", 10, 10000);
  25. print(cout, item1) << endl;
  26. print(cout, item2) << endl;
  27. print(cout, item3) << endl;
  28. return 0;
  29. }

上面的类运行成立,

情况1

[cpp] view
plain
 copy

  1. 去掉 Sales_data( ) = default;

报错,没有定义默认构造函数,当我们自己定义了其他任何一种构造函数时,编译器就不会帮我们合成默认构造函数。

情况2

当我们不提供类内初始值(c++11)时,默认构造函数不会帮我们初始化内置类型,如int, double等等。

情况3

使用流初始化的构造函数

[cpp] view
plain
 copy

  1. Sales_data(std::istream &is)
  2. {
  3. read(is, *this);//read从is中读取一条信息存到this对象中。
  4. }
  5. main()
  6. {
  7. Sales_data item(cin);   //就会从流中读取一条信息。
  8. }

简单的使用流初始化。

[cpp] view
plain
 copy

  1. int main()
  2. {
  3. Sales_data total(cin);
  4. while(1)
  5. {
  6. Sales_data item(cin);//不能写到while循环里,会报错
  7. if(total.isbn() == item.isbn())
  8. total.combine(item);
  9. else
  10. {
  11. print(cout, total);
  12. total = item;
  13. }
  14. }
  15. print(cout, total);
  16. return 0;
  17. }

6.访问控制和封装

使用访问控制符增加类的封装性

public:    成员可以在整个程序内被访问,public定义类的接口

private:   成员可以被类的成员函数访问,但是不能被使用该类的代码访问,private部分封装了类的实现细节

我们也可以使用struct 和 class 定义类( 它俩的唯一区别就是默认的访问权限 )

struct 在第一个限定符之前默认是public的

class 在第一个限定符之前默认是private的

7.友元

类允许其他类或者函数访问它的非公有成员,方法是令其他类或函数成为它的友元

如果想把一个函数作为友元,只需要添加一条以friend关键字开头的函数声明即可

[cpp] view
plain
 copy

  1. friend std::istream& read(std::istream &is, Sales_data &rhs);
  2. //注意如果read函数在其他.h文件中定义,我们必须在用它的类的.h文件中先声明它在设置为友元

一般来说,最好在类定义开始或结束前的位置集中声明友元

类还可以把其他的类定义成友元,也可以把其他类(之前定义过的)的成员函数定义为友元。

此外,友元函数能定义在类的内部,这样的函数是隐式内联的

如果类指定的友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员。

令成员函数作为友元

!当把一个成员函数声明为友元时,我们必须明确指出该成员函数属于哪个类

明确组织结构!

。。。

重载函数作为友元,尽管名字相同,但是他们依然是不同的函数。要分别对每一个函数进行声明

就算在内部定义友元函数,我们也应该在外部声明它使得它可见。

8.可变数据成员

用mutable修饰的成员永远不会是const ,即使出现在const函数中

[cpp] view
plain
 copy

  1. #include <iostream>
  2. class A
  3. {
  4. public:
  5. void b(void)const
  6. {
  7. i++;
  8. std::cout << m << std::endl;
  9. std::cout << i << std::endl;
  10. }
  11. private:
  12. int m = 0;
  13. mutable int i = 0;
  14. static int k;
  15. //static int k = 0;  error:只能定义不能初始化static成员
  16. //const static int k = 0   正确:但是只能是int型, 其他double,string都不行。
  17. };
  18. int main()
  19. {
  20. A a;
  21. for(int j = 0; j < 10; j++)
  22. a.b();
  23. }

可在const 函数中修改mutable成员。

但是从上面的函数又引出来了一个问题

[cpp] view
plain
 copy

  1. 当我把
  2. mutable int i = 0;
  3. 替换成
  4. mutable static int i =0;

会报错:

245.cpp:32:32: error: conflicting specifiers in declaration of ‘i’

245.cpp: In member function ‘void A::b() const’:

245.cpp:25:13: error: ‘i’ was not declared in this scope

因为类的对象实例化是在一个指定的区域

再举个例子,说明类中static变量怎么用

[cpp] view
plain
 copy

  1. #include <iostream>
  2. #include <string>
  3. class T
  4. {
  5. public:
  6. T():i(10) { }
  7. void A(void)
  8. {
  9. i++;
  10. std::cout << i << std::endl;
  11. std::cout << j << std::endl;
  12. }
  13. private:
  14. int i;
  15. static int j;
  16. };
  17. int T::j = 10;
  18. int main()
  19. {
  20. T t;
  21. t.A();
  22. }

静态变量j是所有类的实例化对象所共用的,一般初始化我们在main函数之前。

注意:

不带static关键字

必须带上类型和属于哪个类的作用域符号。

static变量存在的区域是全局区,它和类的实体不在一个区域,所以会报错,我们在类中定义static成员不能让类中的函数等访问。

[cpp] view
plain
 copy

  1. 别人博客的一段话
  2. 说完了static成员后,我们再来看看static成员函数,static成员是类的组成部分并不是任何对象的组成部分,
  3. 因此,static成员函数没有this指针。我们知道,一般而言,类中的成员函数具有一个附加的隐含实参,即指向
  4. 该类对象的一个指针。这个隐含实参命名为this。因为static成员函数不是任何对象的组成部分,所以static
  5. 成员函数就没有this形参了。由于成员函数声明为const说明该成员函数不会修改该成员函数所属的对象,所以
  6. static成员函数不能声明为const。为什么呢?因为static成员函数不是任何对象的组成部分。static成员函数
  7. 可以直接访问所属类的static成员,但是不能直接使用非static成员函数!也不能访问static const 类型的成员!

总之static关键字修饰的在内存中存储是在静态区也就是全局区,而新建的类是在栈区。

静态全局变量在声明它的整个文件都是可见的,而在文件之外是不可见的。在函数的返回类型前加上static关键字,函数即被定义为静态函数。静态函数与普通函数不同,它只能在声明它的文件当中可见,不能被其它文件使用。

9.我们希望类开始时总是有默认初始值, 在c++11中,最好的方式就是把这个默认值声明成一个类内初始值。

类内初始值必须以=号或者花括号表示。

[cpp] view
plain
 copy

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. class Window_mgr
  5. {
  6. private:
  7. std::vector<std::string>ivec{"hello"};
  8. //std::vector<std::string>ivec = "hello";
  9. };
  10. int main()
  11. {}

10.返回*this的函数

[cpp] view
plain
 copy

  1. myScreen.mov(4,0).set(‘c‘);

这句话的含义是mov移动到(4,0)位置设置此出的字符为‘c‘。

如果函数mov返回的是非引用类型,代码将不会正确执行,因为此时返回的是*this副本返回

以副本返回输出有可能也是副本,不要错误的认为真实的就改变了。

[cpp] view
plain
 copy

  1. Screen& mov(pos h, pos w)
  2. {
  3. cursor = h*width + w;
  4. return *this;
  5. }

一个const 成员函数以引用的形式返回的*this,那么它的返回类型也是常量引用。

this指针的好处

在类中区分类的变量和类方法的变量

[cpp] view
plain
 copy

  1. #include <iostream>
  2. class A
  3. {
  4. public:
  5. void fun()
  6. {
  7. int a = 5;
  8. std::cout << a << std::endl;     //区分局部变量和成员变量,不过我们尽量不要这样做,可以重新起个名字
  9. std::cout << this->a << std::endl;
  10. }
  11. private:
  12. int a = 10;
  13. };
  14. int main()
  15. {
  16. A n;
  17. n.fun();   //输出结果是5和10
  18. return 0;
  19. }

一个类的所有实例调用的方法在内存中只有一份拷贝,尽管可能存在多个对象,

每个对象在内存中都有一份拷贝,this允许方法为不同的对象工作,每次调用

方法时, this变量会变成引用该方法的特定的实例,方法代码接着会和特定的对象相关联。

11.类的作用域

<1.一个类就是一个作用域的事实能够很好的解释为什么当我们在类的外部定义成员函数时必须同时提供类名和函数名。

<2.返回类型或者任何一个参数类型是类中的,都要指明它属于哪个类。

<3.编译器处理完类中全部的声明参会处理成员函数的定义,因为成员函数体在整个类可见后才会处理,所以他能使用类中定义的任何名字

类型名的定义通常出现在类的开始处,这样就能确保所有使用该类型的成员都出现在类名的定义之后。

<4.可以通过::来访问外部作用域被隐藏的变量。!不过我们应该尽量保证不要隐藏外部作用域可能用到的名字。

12.名字查找与类的作用域

<1.首先,在名字所在的块中寻找其声明语句,只考虑在名字使用之前出现的声明

<2.如果没找到,继续查找外层作用域

<3.如果最终没有找到匹配的报错

类的定义分两步处理

<1.首先编译成员的声明

<2.直到类全部可见后才编译函数体。

13.构造函数在探究

<1 构造函数的初始值列表。

[cpp] view
plain
 copy

  1. string foo = "hello world";
  2. string bar;
  3. bar = "hello ,world";

这两个的区别就是foo直接赋值而避免了构造函数初始化

bar先使用构造函数初始化话了以后在使用赋值。

<2 构造函数的初始值不可少

[cpp] view
plain
 copy

  1. #include <iostream>
  2. class fun
  3. {
  4. public:
  5. void func(){ std::cout << "func" << std::endl; }
  6. fun(): k(1) { }
  7. private:
  8. const int i;    //提供默认函数初始化,但是一旦定义了型如上面的构造函数就会报错,因为不会默认合成构造函数,引用和const就没有被初始化了
  9. int &j;
  10. int k;
  11. };
  12. int main()
  13. {
  14. int i = 10;
  15. int &r = i;   //引用和const必须要初始化。
  16. //int &k;
  17. //const int n;
  18. }

我们初始化const或者引用类型的数据成员唯一的机会就是通过构造函数初始值。

所以!使用构造函数初始值。

<3 成员初始化顺序

成员的初始化顺序与他们在类中定义的顺序一样

[cpp] view
plain
 copy

  1. class A
  2. {
  3. public:
  4. A( int val ) : j(val), i(j);  //报错,先初始化i。
  5. private:
  6. int i;
  7. int j;
  8. }

最好令构造函数初始值的顺序与成员声明的顺序一致,而且如果有可能的话,尽量避免使用某些成员初始化其他成员。

<4 不能两个构造函数都使用默认实参,会产生二义性。

[cpp] view
plain
 copy

  1. Sales_data(std::string s = " "):bookNo(s) { std::cout << "Sales_data(std::string s = " ")" << std::endl; }
  2. Sales_data(std::string s, unsigned cnt, double rev) : bookNo(s), units_sold(cnt), revenue(rev)
  3. { std::cout << "(std::string s, unsigned cnt, double rev) : " << std::endl; }
  4. Sales_data(std::istream &is = std::cin) { read(is, *this); std::cout << "std::istream &i = cin" << std::endl;}

Sales_data(std::string s = " ")会和Sales_data(std::istream &is = std::cin)产生二义性。

因为一但定义

[cpp] view
plain
 copy

  1. Sales_data a;

不知道用那一个构造函数来初始化。

<5 c++11 委托构造函数

一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把它自己的一些(或者全部)职责委托给了其他构造函数

加入委托的构造函数函数体里面包含有代码的话,先执行这些代码,然后控制权才会交还给委托者的函数体

列子

[cpp] view
plain
 copy

  1. #include <iostream>
  2. #include <string>
  3. class Sales_data
  4. {
  5. public:
  6. Sales_data(std::string bn, unsigned us, double re): bookNo(bn), units_sold(us), revenue(re)
  7. { std::cout << "委托Sales_data(std::string bn, unsigned us, double us) \n执行函数体" << "\n"<< std::endl;}
  8. Sales_data(): Sales_data("", 0, 0)               //委托三参版本
  9. { std::cout << "归还Sales_data():Sales_data("", 0, 0) \n执行函数体" << "\n" << std::endl; }
  10. Sales_data(std::string s): Sales_data(s, 0, 0)   //委托三参版本
  11. { std::cout << "归还Sales_data(std::string):Sales_data(s, 0, 0) \n执行函数体" << "\n" << std::endl;}
  12. Sales_data(std::istream &is) : Sales_data()      //委托默认版本,默认版本在委托三参版本。
  13. {
  14. read(is, *this);
  15. std::cout << "执行Sales_data(std::istream &is) \n执行函数体" << "\n" << std::endl;
  16. }
  17. friend std::istream& read(std::istream& is, Sales_data& item);
  18. private:
  19. std::string bookNo;
  20. unsigned units_sold;
  21. double revenue;
  22. };
  23. std::istream& read(std::istream& is, Sales_data& item)
  24. {
  25. is >> item.bookNo >> item.units_sold >> item.revenue;
  26. return is;
  27. }
  28. int main()
  29. {
  30. std::cout << "a" << std::endl;
  31. Sales_data a;
  32. std::cout << "b" << std::endl;
  33. Sales_data b("string");
  34. std::cout << "c" << std::endl;
  35. Sales_data c(std::cin);
  36. }

运行结果

C++没有提供让一个构造函数去委托另一个构造函数执行构造操作的机制。这意味着不能(或不提倡)

使用缺省参数,类的维护者不得不编写并维护多个构造函数。这会导致源代码和目标代码的重复,降低

了可维护性(由于可能引起不一致性),有时还会导致代码膨胀。

14.隐式的类类型转换

我们也能为类定义隐式的转换机制,如果构造函数只接受一个实参,则它实际上定义了转换为此类类型的隐式转换机制,

有时把这种构造函数称为转换构造函数。

[cpp] view
plain
 copy

  1. class Sales_data
  2. {
  3. public:
  4. Sales_data() = default;
  5. Sales_data(std::string s):bookNo(s), units_sold(0), revenue(0) { }
  6. Sales_data(std::istream &is):{ read(is, *this);}
  7. };
  8. Sales_data s1;
  9. string s = "hello";
  10. s1.combine(s);

成立,因为存在只传参string s的构造函数。

那么s1.combine(s);中的s会调用Sales_data的只传参数s的版本的构造函数,那么s1.combine(s)的s就会变成一个Sales_data对象,所以可以调用combine函数。

我们可以抑制构造函数定义的隐式转换,既不能通过穿参数s隐式构造一个Sales_data对象。

通过将构造函数声明为 explicit 加以阻止

[cpp] view
plain
 copy

  1. class Sales_data
  2. {
  3. public:
  4. Sales_data() = default;
  5. explicit Sales_data(std::string s):bookNo(s), units_sold(0), revenue(0) { }
  6. explicit Sales_data(std::istream &is):{ read(is, *this);}
  7. };

7.49题

[cpp] view
plain
 copy

  1. Sales_data combine(Sales_data);
  2. Sales_data combine(Sales_data &);
  3. Sales_data combine(const Sales_data &);

s是一个string 类型的字符串

调用i.combine(s);

[cpp] view
plain
 copy

  1. Sales_data combine(Sales_data);

正确,因为Sales_data是一份副本,会执行构造函数,所以存在隐式转换

[cpp] view
plain
 copy

  1. Sales_data combine(Sales_data &);

错误,因为Sales_data是引用,不会执行构造函数,所以不存在隐式转换,类型不匹配,错误。

[cpp] view
plain
 copy

  1. Sales_data combine(const Sales_data &);

正确,想向const Sales_data &传参数的时候,实际上是先创建一个temp值, 然后让const 修饰这个temp,所以也存在建立的过程

15.static

<1.静态成员函数可以访问静态成员变量和和静态成员函数

<2.非静态成员函数也可以访问静态成员变量和和静态成员函数

<3.静态成员函数没有this指针,无法访问属于类对象的非静态成员变量和非静态成员函数

<4.由于没有this指针的额外开销,因此静态成员函数与类的非静态成员函数相比速度上会有少许的增长

<5.静态成员函数/变量属于整个类,没有this指针,该类的所有对象共享这些静态成员函数/变量

<6.非静态成员函数/变量属于类的具体的对象,this是缺省的

<7.静态成员变量在类内声明,且必须带static关键字;在类外初始化,且不能带static关键字

<8.静态成员函数在类内声明,且必须带static关键字;在类外实现,且不能带static关键字

reference link: http://blog.csdn.net/wwh578867817/article/details/41593553

时间: 2024-08-29 21:20:13

c++ primer 学习笔记(2): 函数 function的相关文章

C++primer学习笔记之函数

1.关于函数原型: 首先,函数的原型说明了函数在调用时候要注意的规则,比如参数的类型和数量,还有一个比较重要的就是函数的返回类型.在函数返回值的时候,他将这个值返回到指定的寄存器或者内存中,然后调用者根据这个返回值的类型才知道在内存中或者寄存器中通过偏移多少来获取到返回值. 并且C++中的风格是不喜欢把函数的定义直接定义在main函数的前面的,所以还是需要写函数原型的.并且在声明函数原型的时候,函数的参数连别中可以不包括变量名,但是要包括类型.并且及时参数名和实际定义的时候不一样也没有关系. 函

C++ Primer学习笔记(三) C++中函数是一种类型!!!

C++中函数是一种类型!C++中函数是一种类型!C++中函数是一种类型! 函数名就是变量!函数名就是变量!函数名就是变量! 重要的事情要说三遍... 接 C++ Primer学习笔记(二) 类的构造函数 与类同名,且无返回类型. 同类的成员函数一样,也可以在类中声明,在类外定义. 格式: 类名(): 成员1(成员1初始化值), 成员2(成员2初始化值) { } 以上,冒号至大括号中间的部分,称为构造函数的初始化列表,用于调用类成员的构造函数来初始化. 没有在初始化列表中显式指定初始化的成员,将会

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr)、C++对象模型

C++ Primer 学习笔记_35_面向对象编程(6)--虚函数与多态(三):虚函数表指针(vptr)及虚基类表指针(bptr).C++对象模型 一.虚函数表指针(vptr)及虚基类表指针(bptr) C++在布局以及存取时间上主要的额外负担是由virtual引起的,包括: virtual function机制:用以支持一个有效率的"执行期绑定": virtual base class:用以实现多次在继承体系中的基类,有一个单一而被共享的实体. 1.虚函数表指针 C++中,有两种数据

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数、抽象类、虚析构函数、动态创建对象

C++ Primer 学习笔记_34_面向对象编程(5)--虚函数与多态(二):纯虚函数.抽象类.虚析构函数.动态创建对象 一.纯虚函数 1.虚函数是实现多态性的前提 需要在基类中定义共同的接口 接口要定义为虚函数 2.如果基类的接口没办法实现怎么办? 如形状类Shape 解决方法 将这些接口定义为纯虚函数 3.在基类中不能给出有意义的虚函数定义,这时可以把它声明成纯虚函数,把它的定义留给派生类来做 4.定义纯虚函数: class <类名> { virtual <类型> <函

C++ Primer 学习笔记33_面向对象编程(4)--虚函数与多态(一):多态、派生类重定义、虚函数的访问、 . 和-&gt;的区别、虚析构函数、object slicing与虚函数

C++ Primer学习笔记33_面向对象编程(4)--虚函数与多态(一):多态.派生类重定义.虚函数的访问. . 和->的区别.虚析构函数.object slicing与虚函数 一.多态 多态可以简单地概括为"一个接口,多种方法",前面讲过的重载就是一种简单的多态,一个函数名(调用接口)对应着几个不同的函数原型(方法). 更通俗的说,多态行是指同一个操作作用于不同的对象就会产生不同的响应.或者说,多态性是指发出同样的消息被不同类型的对象接收时有可能导致完全不同的行为. 多态行分

C++ Primer 学习笔记_24_类与数据抽象(10)--static 与单例模式、auto_ptr与单例模式、const成员函数、const 对象、mutable修饰符

C++ Primer 学习笔记_24_类与数据抽象(10)--static 与单例模式.auto_ptr与单例模式.const成员函数.const 对象.mutable修饰符 前言 [例]写出面向对象的五个基本原则? 解答:单一职责原则,开放封闭原则,依赖倒置原则,接口隔离原则和里氏替换原则 里氏替换原则:子类型必须能够替换他们的基类型. 设计模式分为三种类型:创建型模式.结构型模式和行为型模式 一.static 与单例模式 1.单例模式 单例模式的意图:保证一个类仅有一个实例,并提供一个访问它

C++ Primer 学习笔记_70_面向对象编程 --纯虚函数、容器与继承

面向对象编程 --纯虚函数.容器与继承 I.纯虚函数 在函数形参后面写上 =0 以指定纯虚函数: class Disc_item : public Item_base { public: double net_price(size_t) const = 0; //指定纯虚函数 }; 将函数定义为纯虚函数能够说明,该函数为后代类型提供了可以覆盖的接口,但是这个类的版本绝不会调用.重要的是,用户将不能创建Disc_item类型的对象. Disc_item discount; //Error Bulk

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符、成员函数方式重载、友元函数方式重载

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符.成员函数方式重载.友元函数方式重载 引言: 明智地使用操作符重载可以使类类型的使用像内置类型一样直观! 一.重载的操作符名 像任何其他函数一样,操作符重载函数有一个返回值和一个形参表.形参表必须具有操作符数目相同的形参.比如赋值时二元运算,所以该操作符函数有两个参数:第一个形参对应着左操作数,第二个形参对应右操作数. 大多数操作符可以定义为成员函数或非成员函数.当操作符为成员函数时,它的第一个操作数隐式绑定

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载、覆盖与隐藏、类型转换运算符、*运算符重载、-&gt;运算符重载

C++ Primer 学习笔记_28_操作符重载与转换(3)--成员函数的重载.覆盖与隐藏.类型转换运算符.*运算符重载.->运算符重载 一.成员函数的重载.覆盖与隐藏 对于类层次的同名成员函数来说,有三种关系:重载.覆盖和隐藏,理清3种关系,有助于写出高质量的代码. 1.成员函数的重载 重载的概念相对简单,只有在同一类定义中的同名成员函数才存在重载关系,主要特点时函数的参数类型和数目有所不同:但不能出现函数参数的个数和类型均相同,仅仅依靠返回值类型不同来区分的函数,这和普通函数的重载是完全一致