Noobzhang

  • 首页

  • 标签

  • 分类

  • 归档

C++ public/protected/private

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

C++ public protected private关键字
用于成员变量,成员函数权限的设置;以及用于类继承权限的设置。

1. 成员权限设置

权限 类内部 该类对象 子类(派生类) 友元函数
private 可访问 不可访问 不可访问 可访问
public 可访问 可访问 可访问 可访问
protected 可访问 不可访问 可访问 可访问

2. 类继承权限设置

C++的类和对象的权限(相对于基类成员)

继承方式 基类对象 派生类继承的基类成员权限变化 派生类对象
public 可访问 public->public
protected->protected
private->private
可访问
protected 不可访问 public->protected
protected->protected
private->private
不可访问
private 不可访问 public->private
private->private
protected->private
不可访问

C++的static用法

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

C++ 中static 关键字用法可以从两个方面来区分,一个是面向过程,另一个是面向对象。面向过程有三种用法,面向对象有两种用法。下文将详细讲解。

用法详解(从作用域,生命周期角度来解释)

面向过程

文件内全局static变量 (和C一样)
作用域:本文件内
生命周期:程序退出

函数内static变量 (和C一样)
作用域:本函数内
生命周期:程序退出

面向对象

类中static成员变量
用法:使用时不用实例化,与类实例无关。(静态数据成员存储在全局数据区,静态数据成员定义时要分配空间,所以不能在类声明中定义。应该在类外定义。此外,在类体外定义时不能指定static关键字)。
初始化格式:<数据类型><类名>::<静态数据成员> = <值>
作用域:遵从类的public、private、protected访问规则
生命周期:程序退出

类中static成员方法
用法:可以引用static成员变量。无法访问属于类对象的非静态数据成员变量/函数。此外,类体外定义时不能指定static关键字
调用static成员方法方式: XClass::xxx_static_fun()、XClassInstant.xxx_static_fun()、XClassInstantP->xxx_static_fun()
作用域:遵从类的public、private、protected访问规则
生命周期:N/A

附1(可执行文件内存布局)

exec_view.bmp

  1. .text 代码段存放可执行指令
  2. .data 初始化后数据 {
    a. 只读数据区(const全局变量 字符串)
    b. 已初始化可读数据区——全局区(全局变量)
    c. 已初始化可读数据区——全局静态区(static全局变量)
  3. .bss 未初始化数据(只记录数据需要多少空间,不为其真正分配内存)
    a. 未初始化静态和全局变量
  4. .heap 运行时malloc动态分配的数据占用空间
    a. 动态内存分配
  5. .stack 函数运行时分配的自动变量占用空间
    a. 局部变量、函数参数
  6. 从可执行文件a.out的角度来讲,如果一个数据未被初始化那就不需要为其分配空间,所以.data和.bss一个重要的区别就是.bss并不占用可执行文件的大小,它只是记载需要多少空间来存储这些未初始化数据,而不分配实际的空间

附2(参考)

http://blog.csdn.net/kerry0071/article/details/25741425/

Java语言

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 Java

C++的const用法

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

C++ const 允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,这样可以获得编译器的帮助。
const 有几种用法。下面将详细讲解。

  1. const 全局变量

    用法: const int a;           //     const data
          const int *p;          //     const data, non-const pointer
          int * const p;         // non-const data, const pointer
          const int * const p;   //     const data, const pointer
    
  2. const 函数局部变量 (包括函数参数、返回值等)

    用法:const int a; const int *p;int * const p;const int * const p;
         const int* function(const int *a);  // 返回值必须传给const data,non-const pointer 的变量
         void int function(const int& a);
    
  3. const 成员变量

    用法:成员常量不能被修改,只能在构造函数初始化列表中赋值
    
  4. const 成员方法

    用法: 不能修改任何成员变量(mutable修饰的变量除外),不能调用非const成员函数
    定义格式:void function() const {}
    
  5. const 类对象、类指针、类引用
  1. 将Const类型转化为非Const类型的方法
    采用const_cast 进行转换。该运算符用来修改类型的const或volatile属性。

C++ 友元

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

C++ 友元
友元机制,开个后门,以让友元函数、类可以访问类内部私有成员。不过这个机制也破坏了类的封装性。

1. 友元函数(这种函数是类外部定义函数)

友元函数是类外部定义的函数,而将函数声明加friend放在需要访问的类的内部。

#include
using namespace std;
class A
{
public:
friend void set_show(int x, A &a); //该函数是友元函数的声明
private:
int data;
};

void set_show(int x, A &a) //友元函数定义,为了访问类A中的成员
{
a.data = x;
cout << a.data << endl;
}

int main(void)
{
class A a;

set_show(1, a);

return 0;

}

2. 友元类

友元类的所有成员函数都是另一个类的友元函数。声明加friend放在需要访问的类的内部。

关于友元类的注意事项:
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。

#include
using namespace std;

class A
{
public:
friend class C; //这是友元类的声明
private:
int data;
};

class C //友元类定义,为了访问类A中的成员
{
public:
void set_show(int x, A &a) { a.data = x; cout<<a.data<<endl;}
};

int main(void)
{
class A a;
class C c;

c.set_show(1, a);

return 0;

}

3. 友元成员函数

类A的成员函数是类B的友元函数。

class B;

class A {
public:
friend void B::B_is_A_friend_function(A & tempA);

private:
int a;
};

class B{
public:
void B::B_is_A_friend_function(A & tempA) {
cout << tempA.a << endl;
}
};

C++的类型转换——隐式、显式转换(xxx_cast)

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

第一部分. 隐式类型转换

算数运算float + int => float  、  赋值int = float、传参、返回值

第二部分.显式类型转换

C风格
    (type) value

C++风格
    static_cast、dynamic_cast、reinterpret_cast和const_cast 
阅读全文 »

C++的类型转换——隐式、显式转换(xxx_cast)

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

第一部分. 隐式类型转换

算数运算float + int => float  、  赋值int = float、传参、返回值

第二部分.显式类型转换

C风格
    (type) value

C++风格
    static_cast、dynamic_cast、reinterpret_cast和const_cast 
阅读全文 »

C++ STL之vector list map set

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

STL C++中有两种类型的容器:顺序容器和关联容器,顺序容器主要有:vector、list、deque等。其中vector表示一段连续的内存地址,基于数组的实现,list表示非连续的内存,基于链表实现。deque与vector类似,但是对于首元素提供删除和插入的双向支持。关联容器主要有map和set。map是key-value形式的,set是单值。map和set只能存放唯一的key值,multimap和multiset可以存放多个相同的key值。

容器类自动申请和释放内存,我们无需new和delete操作。

vector

一段连续的内存地址,基于数组的实现

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
#include<vector>
//1. 定义和初始化
vector<int> vec1; 默认初始化,vec1为空
vector<int> vec2(vec1); //使用vec1初始化vec2
vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
vector<int> vec4(10); //10个值为0的元素
vector<int> vec5(10,4); //10个值为4的元素
//add/remove
vec1.push_back(int) //尾部添加元素
vec1.insert(vec1.end(),5,3); //从vec1.back位置插入5个值为3的元素
vec1.pop_back(); //删除末尾元素
vec1.erase(vec1.begin(),vec1.begin()+2);//删除vec1[0]-vec1[2]之间的元素,不包括vec1[2]其他元素前移

vector<int>::iterator iter = vec1.begin(); //获取迭代器首地址
vector<int>::const_iterator c_iter = vec1.begin(); //获取const类型迭代器

vec1.clear(); //清空元素

//2. check, compare and size
vec1.size()
vec1.empty()
(vec1==vec2)

//3. read/write
vec1[0]

//4. 遍历
int length = vec1.size(); //下标法
for(int i=0;i<length;i++) {
cout<<vec1[i];
}

vector<int>::iterator iter = vec1.begin(); //迭代器法
for(;iter != vec1.end();iter++) {
cout<<*iter;
}

#deque
deque与vector类似,但是对于首元素提供删除和插入的双向支持
deque还支持从开始端插入数据:push_front。其余的类似vector操作方法的使用.

list

表示非连续的内存,基于链表实现

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
#include<list>
//1.定义和初始化
list<int> lst1; //创建空list
list<int> lst2(3); //创建含有三个元素的list
list<int> lst3(3,2); //创建含有三个元素为2的list
list<int> lst4(lst2); //使用lst2初始化lst4
list<int> lst5(lst2.begin(),lst2.end()); //同lst4

//2.常用操作方法
lst1.assign(lst2.begin(),lst2.end()); //分配值,3个值为0的元素
lst1.push_back(10); //末尾添加值
lst1.pop_back(); //删除末尾值
lst1.begin(); //返回首值的迭代器
lst1.end(); //返回尾值的迭代器
lst1.clear(); //清空值
bool isEmpty1 = lst1.empty(); //判断为空
lst1.erase(lst1.begin(),lst1.end()); //删除元素
lst1.front(); //返回第一个元素的引用
lst1.back(); //返回最后一个元素的引用
lst1.insert(lst1.begin(),3,2); //从指定位置插入个3个值为2的元素
lst1.rbegin(); //返回第一个元素的前向指针
lst1.remove(2); //相同的元素全部删除
lst1.reverse(); //反转
lst1.size(); //含有元素个数
lst1.sort(); //排序
lst1.unique(); //删除相邻重复元素
//3.遍历 迭代器法
for(list<int>::const_iterator iter = lst1.begin();iter != lst1.end();iter++)
{
cout<<*iter;
}

map<K, V>

key-value形式的,对于迭代器来说,可以修改实值,而不能修改key。map会根据key自动排序.

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
#include<map>
//1.定义和初始化
map<int,string> map1; //空map

//2.常用操作方法
map1[3] = "Saniya"; //添加元素
map1.insert(map<int,string>::value_type(2,"Diyabi"));//插入元素
//map1.insert(pair<int,string>(1,"Siqinsini"));
map1.insert(make_pair<int,string>(4,"V5"));
string str = map1[3]; //根据key取得value,key不能修改
map<int,string>::iterator iter_map = map1.begin();//取得迭代器首地址
int key = iter_map->first; //取得key
string value = iter_map->second; //取得value
map1.erase(iter_map); //删除迭代器数据
map1.erase(3); //根据key删除value
map1.size(); //元素个数
map1.empty(); //判断空
map1.clear(); //清空所有元素

//3.遍历
for(map<int,string>::iterator iter = map1.begin();iter!=map1.end();iter++)
{
int keyk = iter->first;
string valuev = iter->second;
}

set

set的含义是集合,它是一个有序的容器,里面的元素都是排序好的支持插入、删除、查找等操作,就像一个集合一样,所有的操作都是严格在logn时间内完成,效率非常高。set和multiset的区别是:set插入的元素不能相同,但是multiset可以相同,set默认是自动排序的,使用方法类似list。

From:https://www.cnblogs.com/cxq0017/p/6555533.html

C++ virtual

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 C++

C++ 中virtual 用于修饰函数,标记函数可以动态绑定

  1. 虚函数
  2. 纯虚函数(基类为抽象类)

虚函数表

编译器会给带虚函数的类添加一个虚函数表指针

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
class Base {
public:
virtual void v1() { cout << "Call Base::v1" << endl; }
virtual void v2() { cout << "Call Base::v2" << endl; }
};

class Sub : public Base {
public:
virtual void v2() { cout << "Call Sub::v2" << endl; }
void v3() { cout << "Call Sub::v3" << endl; }
};

int main () {
//Only to explore principle
cout << "size of Base: "<<sizeof(Base) << endl; //4 bytes

typedef void(*Func)(void);
Base b;
Base *sPtr = new Sub(); //Sub的ptr

long* vptr = (long*)(*(long*)sPtr) //Sub的ptr地址中第一个四字节是_vptr,即虚拟表指针。
Func v1 = (Func)vptr[0]; //
Func v2 = (Func)vptr[1]; //

v1(); //Base::v1
v2(); //Sub::v2

//Normal code
Base *bPtr = new Sub();
bPtr->v1(); //静态调用基类v1
bPtr->v2(); //动态调用派生类v2
//bPtr->v3(); //编译都不能通过,基类没有v3成员,而且也没有开通动态绑定,无法定位到派生类的v3。

return 0;
}

基类和派生类中虚函数内存示意图

单继承
003_CPP_vptr.png

多重继承
003_CPP_vptr2.png

From : https://www.cnblogs.com/hushpa/p/5707475.html

附:C++中的类所占内存空间
类所占内存的大小是由成员变量(静态变量除外)决定的,成员函数(这是笼统的说,后面会细说)是不计算在内的。
class CBase {}; //sizeof(CBase)=1; (C++要求每个实例在内存中都有独一无二的地址)
class CBase { int a; char p; }; //sizeof(CBase)=8; (4字节对齐)
class CBase { public: CBase(void); virtual ~CBase(void); //sizeof(CBase)=12 (虚拟函数表指针_vptr占4个字节)
private: int a; char *p; };
class CSub : public CBase { public: CSub(void); ~CSub(void); virtual void test(); //sizeof(CSub)=16 (Base12+Sub4 以及共用_vptr)
private: int b; };

static修饰的静态变量:不占用内容,原因是编译器将其放在全局变量区。

Java public/protected/private

发表于 2016-05-28 | 更新于 2019-03-08 | 分类于 Java

用于修饰类或者修饰成员变量。

1. 基本规则

public(公有访问权限)

修饰类成员变量/方法 //基类和派生类可见
修饰类 //公共类,所有包可见
?修饰内部类?

protected(继承访问权限)

修饰类成员变量/方法 //基类和派生类可见
修饰内部类 //基类和派生类可见;包内可见

default (friendly) (包访问权限)

默认权限是包内访问。即未指定权限关键字的类成员,只有包内的类的成员方法才可以访问。
类无修饰: 包内可见
成员变量/方法无修饰: 包内可见
内部类无修饰: 包内可见?

private(私有访问权限)

修饰类成员变量/方法 //基类可见
修饰内部类 //基类可见

继承派生权限

Java 使用extends关键字进行派生基类,只有公共继承

1. public 用法示例

/Animal.java/
package me.jingg.java; //Java 以包为访问单元(一个包可有多个文件多个类)

public abstract class Animal { //公共类: 可以通过import me.jingg.java.Animal 继承使用
protected String name;
protected int age;

private void eatBase() {}
public void eat() {}
public void run() {}
public void showInfo() {}

}

/AccessRule.java/
package me.jingg.java;
//一个Java文件只能有一个public类(public的类名必须与文件名一致),一个Java文件是一个编译单元,每个编译单元都有单一的公共接口—即public类
public class AccessRule extends Animal implements xxx { //公共类: 可以通过import me.jingg.java.AccessRule 引用
private eat_fish_num; //static一般在有初始值的,值固定的 (private表示私有) (final: 1.不能再改;2.不会被重载; 3.不会被继承.)

public static void main(int argc, char **argv) {

}

}

2. 抽象接口

1…5678

Jin

77 日志
9 分类
113 标签
© 2019 Jin
由 Hexo 强力驱动 v3.8.0
|
主题 – NexT.Mist v7.0.0