【前言】二者的区别就不介绍了。二者使用方法:

printf("%s",a);

cout<<a<<endl;

   endl的作用是什么?

一、endl作用

  众所周知,endl有一个换行的作用,第二个作用就是清空缓冲区buffer。

  为什么要清空缓冲区呢?

  首先思考缓冲区存在的作用,缓冲区的作用一是为了避免频繁的I/O操作对磁盘的损耗,二是减少存取时的函数调用的损耗。所以,c++里面的缓冲区意义是非常大的,注意printf是没有缓冲区的。

  我们上面即使没有加上endl,输出也会马上输出出来,那清空缓冲区的作用在哪呢?其实,我们这个程序太简单,不能体现。但是cout什么时候清空缓冲区我们是不确定的,这对于多线程来说增加了不可控,多线程只有栈区独享,所有线程共享原主进程的缓冲区,如果不及时清空缓冲区可能会造成串数据;cin更是从缓冲区读取数据,其中很多细节。

二、cout和printf时间复杂度比较

  cout是对"<<”运算符的重载。其运行时间也慢于printf。有人做的测评:https://blog.csdn.net/eternity666/article/details/78001513

  在vs下cout是对printf的封装,还要保持同步。但是在g++下不是,有人做的测试,g++的cout速度反而比printf快10倍左右。https://blog.csdn.net/qq_26398495/article/details/55105094

  所以,在linux端编程,用cout就可以,没必要用printf.,而且更加明晰。

三、printf怎么实现“C多态”?

  今天有个同学考我一个题目,很有意思。我们知道printf的参数列表,参数个数是不确定的,这就很类似C++里面的多态,那printf是怎么实现C“多态”的呢?

  我第一次思考这个问题,就先写下当时怎么思考的吧?当然,他的问题是没有回答上来。

  T1、C++里面的多态是怎么实现的?

  C++是静态编译型语言,所谓的静态联编,但是使用虚函数即可实现动态联编,类似动态链接库。实现方法就是编译器提前生成vptr指针,运行的时候在通过指针找到虚函数表,找到函数入口地址。从指针的角度,好像和C多态有点关系,用函数指针?

  顺着这个思路,我们知道,多态有编译期多态和运行期多态。编译期->重载,运行期->重写。

  T2、重载重写(重定义?)三者的区别 
       (1)成员函数重载特征:
      相同的范围(在同一个类中);
      函数名字相同
      参数不同;
      virtual关键字可有可无;
  (2) 重写(覆盖)是指派生类函数覆盖基类virtual函数,特征是:
      不同的范围,分别位于基类和派生类中;
      函数的名字相同;
      参数相同;
      基类函数必须有virtual关键字;
  (3)重定义(隐藏)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
      如果派生类的函数和基类的函数同名,但是参数不同,此时,不管有无virtual,基类的函数被隐藏;
      如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有vitual关键字,此时,基类的函数被隐藏。
  (条款36:不应该重定义任何非虚函数,既然需要你重定义,那为什么不直接在基类定义虚函数?非虚函数就是表明此函数具有“不变性凌驾特异性”,所以尽量不要重定义)

  T3、C++里面的运行期和编译期多态

  (1)运行期多态(重写)

  运行期多态的设计思想要归结到类继承体系的设计上去。对于有相关功能的对象集合,我们总希望能够抽象出它们共有的功能集合,在基类中将这些功能声明为虚接口(虚函数),然后由子类继承基类去重写这些虚接口,以实现子类特有的具体功能。典型地我们会举下面这个例子:

class Animal
{
public :
virtual void shout() = 0;
};
class Dog :public Animal
{
public:
virtual void shout(){ cout << "汪汪!"<<endl; }
};
class Cat :public Animal
{
public:
virtual void shout(){ cout << "喵喵~"<<endl; }
};
class Bird : public Animal
{
public:
virtual void shout(){ cout << "叽喳!"<<endl; }
}; int main(){
Animal * anim1 = new Dog;
Animal * anim2 = new Cat;
Animal * anim3 = new Bird;
//藉由指针(或引用)调用的接口,在运行期确定指针(或引用)所指对象的真正类型,调用该类型对应的接口
anim1->shout();
anim2->shout();
anim3->shout();
//delete 对象
...
return 0;
}

  运行期多态的实现依赖于虚函数机制。当某个类声明了虚函数时,编译器将为该类对象安插一个虚函数表指针,并为该类设置一张唯一的虚函数表,虚函数表中存放的是该类虚函数地址。运行期间通过虚函数表指针与虚函数表去确定该类虚函数的真正实现。

  总结:运行期多态通过虚函数发生于运行期

  (2)编译期多态(重载)

  对模板参数而言,多态是通过模板具现化和函数重载解析实现的。以不同的模板参数具现化导致调用不同的函数,这就是所谓的编译期多态。相比较于运行期多态,实现编译期多态的类之间并不需要成为一个继承体系,它们之间可以没有什么关系,但约束是它们都有相同的隐式接口。我们将上面的例子改写为:

class Animal
{
public :
void shout() { cout << "发出动物的叫声" << endl; };
};
class Dog
{
public:
void shout(){ cout << "汪汪!"<<endl; }
};
class Cat
{
public:
void shout(){ cout << "喵喵~"<<endl; }
};
class Bird
{
public:
void shout(){ cout << "叽喳!"<<endl; }
};
template <typename T>
void animalShout(T & t){
t.shout();
}
int main(){
Animal anim;
Dog dog;
Cat cat;
Bird bird;
animalShout(anim);
animalShout(dog);
animalShout(cat);
animalShout(bird);
getchar();
}

    在编译之前,函数模板中t.shout()调用的是哪个接口并不确定。在编译期间,编译器推断出模板参数,因此确定调用的shout是哪个具体类型的接口。不同的推断结果调用不同的函数,这就是编译器多态。这类似于重载函数在编译器进行推导,以确定哪一个函数被调用。

  (3)二者的区别:超链接

  T3、那么C实现“多态”是和C++ 类似的吗?

  (1)重载实现(编译期)

  看printf的源码:

 1 #include <stdio.h>
2 #include <stdarg.h>
3
4
5 //va_start(arg,format),初始化参数指针arg,将函数参数format 右边第一个参数地址赋值给arg
6 //format必须是一个参数的指针,所以,此种类型函数至少要有一个普通的参数, 
7 //从而提供给va_start ,这样va_start才能找到可变参数在栈上的位置。 
8 //va_arg(arg,char),获得arg指向参数的值,同时使arg指向下一个参数,char用来指名当前参数型
9 //va_end 在有些实现中可能会把arg改成无效值,这里,是把arg指针指向了 NULL,避免出现野指针 
10
11
12 void printf(const char *format, ...)
13 {
14 va_list arg;
15 va_start(arg, format);
16
17 while (*format)
18 {
19 char ret = *format;
20 if (ret == '%')
21 {
22 switch (*++format)
23 {
24 case 'c':
25 {
26 char ch = va_arg(arg, char);
27 putchar(ch);
28 break;
29 }
30 case 's':
31 {
32 char *pc = va_arg(arg, char *);
33 while (*pc)
34 {
35 putchar(*pc);
36 pc++;
37 }
38 break;
39 }
40 default:
41 break;
42 }
43 }
44 else
45 {
46 putchar(*format);
47 }
48 format++;
49 }
50 va_end(arg);
51 }
52 int main()
53 {
54 printf("%s %s %c%c%c%c%c!\n", "welcome", "to", 'C', 'h', 'i', 'n', 'a');
    printf("%s %c","abc","c");//重载了使用
55     system("pause");
56 return 0;
57 }

  void printf(const char *format,...);。注意到"..."这个可变参东西了吧,printf的“...”内部实际上是通过 __VA_ARGS__ 这个宏来实现的:链接。他有三个参数,具体可参考:这里

  (2)重写(运行期)

  这个就要通过函数指针了吧:https://blog.csdn.net/philip_puma/article/details/25973139

 

 

由endl对printf和cout的思考的更多相关文章

  1. 指向字符串的指针在printf与cout区别

    根据指针用法: * 定义一个指针, &取变量地址, int b = 1; int *a = &b; 则*a =1,但对于字符串而言并非如此,直接打印指向字符串的指针打印的是地址还是字符 ...

  2. c++:printf和cout那个更好更快些

    现在群里在讨论cout和printf那个快的问题,但我个人觉得printf好: 因为:printf对于一些数据大,以及保留小数位,字符……可以显示出明显的优势如“%s %d %c…………” 虽然pri ...

  3. c++ printf和cout的性能

    今天做了一道编程题,仔细检查了算法并没有错误,但是结果显示时间超时,但仍有80%的案例通过了,很奇怪. 通过将cin换成scanf,cout换成printf结果AC,实验发现二者性能差了很多,在输出1 ...

  4. printf和cout的区别详述

    https://blog.csdn.net/ysayk/article/details/50959909

  5. 8-cin cout PK scanf printf(速度快慢问题对比)

    我们在c++ 中使用cin cout很方便但速度很慢,导致有些题目用cin就超时而用scanf则就ac了,那到底改用谁? cin慢是有原因的,其实默认的时候,cin与stdin总是保持同步的,也就是说 ...

  6. C语言中printf与i++,C++中的cout

    一,printf与i++ 1,C语言中的printf是自右向左输出,. 2,而i++与++i不同的 i++首先取得i的值,下一行时候i = i + 1: ++i,首先i = i + 1,再取得i的值. ...

  7. C++ 学习笔记(一) cout 与printf 的不同之处

    作为一个嵌入式开发的猿,使用打印调试程序是必不可少的,拿到新的项目第一件事就是捣鼓打印.这次也不例外有打印才有耍下去的底气.在之前零零碎碎的C++学习中,还是一边学一边做项目的状态下能用printf解 ...

  8. [笔记]cin、cout与scanf、printf的效率差异对比分析

    之前上传UVa227 puzzle时,好不容易AC了,但发现自己用时50(ms),而在VJ上看到人家都是40ms.20ms,于是打开一个20ms的代码查看人家强在哪里.但结果研究了半天感觉差不多,于是 ...

  9. printf scanf cin cout的区别与特征

    printf和scanf是c语言的输入输出,学习c++以后,自然是用cin cout这两个更简单的输入输出 printf scanf 都需要进行格式控制,比较麻烦,但优点是速度比较快,毕竟多做了一些事 ...

随机推荐

  1. Codeforces Round #635 (Div. 2)

    Contest Info Practice Link Solved A B C D E F 4/6 O O Ø  Ø     O 在比赛中通过 Ø 赛后通过 ! 尝试了但是失败了 - 没有尝试 Sol ...

  2. 2019 ICPC 上海区域赛总结

    2019上海区域赛现场赛总结 补题情况(以下通过率为牛客提交): 题号 标题 已通过代码 通过率 我的状态 A Mr. Panda and Dominoes 点击查看 5/29 未通过 B Prefi ...

  3. Testing Beta Round (Unrated)

    比赛链接:https://codeforces.com/contest/1390 A. 123-sequence 题意 给出一个只含有 $1,2,3$ 的数组,问使所有元素相同至少要替换多少元素. 题 ...

  4. HDU5213 Lucky【容斥+莫队】

    HDU5213 Lucky 题意: 给出\(N\)个数和\(k\),有\(m\)次询问,每次询问区间\([L1,R1]\)和区间\([L2,R2]\)中分别取一个数能相加得到\(k\)的方案数 题解: ...

  5. 【noi 2.6_9272】偶数个数字3(DP)

    题意:问所有的N位数中,有多少个有偶数个数字3的数. 解法:f[i][j]表示i位数中含数字3的个数模2为j的个数.于是分第i位填3还是不填3讨论. 小tip:要模12345:for循环新定义了一个变 ...

  6. ef实现左关联查询

    在EF中,当在dbset使用join关联多表查询时,连接查询的表如果没有建立相应的外键关系时,EF生成的SQL语句是inner join(内联),对于inner join,有所了解的同学都知道,很多时 ...

  7. 1.nginx安装和基本配置

    作者 微信:tangy8080 电子邮箱:914661180@qq.com 更新时间:2019-07-10 20:56:10 星期三 欢迎您订阅和分享我的订阅号,订阅号内会不定期分享一些我自己学习过程 ...

  8. js的变量,作用域,内存

    一,基本类型和引用类型的值基本类型的值是按值访问的,引用类型的值是保存在内存中的对象1,动态的属性 只有引用类型的值可以添加属性方法 不能给基本类型添加属性和方法2,复制变量值 复制基本类型的值,两个 ...

  9. how to read the system information by using the node cli tool?

    how to read the system information by using the node cli tool? node cli & get system info demos ...

  10. WebVR & CSS 3D & WebGL

    WebVR & CSS 3D & WebGL VR https://developer.mozilla.org/en-US/docs/Web/API/WebVR_API https:/ ...