虚函数
虚函数是一种c++的机制,它允许一个类的子类能够重写(override)
父类的函数,实现它自己独特的功能。
下面是一个例子
#include <iostream>
#include <string>
class Entity
{
public:
virtual std::string GetName() {
return "Entity";
}
Entity() {
};
~Entity() {
};
private:
};
class Player : public Entity {
private:
std::string m_name;
public:
Player(const std::string& name) {
m_name = name;
}
std::string GetName() override{
return m_name;
}
};
int main() {
Entity* e = new Entity;
std::cout << e->GetName() << std::endl;
Player* p = new Player("wsxk");
std::cout << p->GetName() << std::endl;
Entity* e2 = new Player("test");
std::cout << e2->GetName() << std::endl;
}
可以看出,虚函数还有一个作用就是使得 父类指针指向子类对象时(总是成立,因为子类是父类的超集,所以父类有的方法,子类也都有)可以正确的使用子类方法。
纯虚函数
纯虚函数只要声明在这个类中,这个类就无法实例化对象,且强制要求该类子类必须实现纯虚函数的定义。
#include <iostream>
#include <string>
class Printable {
public:
virtual std::string GetClassName() = 0;
};
class Entity: public Printable
{
public:
virtual std::string GetName(){
return "Entity";
}
Entity() {
};
~Entity() {
};
std::string GetClassName() override{
return "Entity";
}
private:
};
class Player : public Entity {
private:
std::string m_name;
public:
Player(const std::string& name) {
m_name = name;
}
std::string GetName() override{
return m_name;
}
std::string GetClassName() override{
return "Player";
}
};
void PrintClassName(Printable * obj) {
std::cout << obj->GetClassName() << std::endl;
}
int main() {
Entity* e = new Entity;
PrintClassName(e);
//std::cout << e->GetName() << std::endl;
Player* p = new Player("wsxk");
PrintClassName(p);
//std::cout << p->GetName() << std::endl;
//Entity* e2 = new Player("test");
//std::cout << e2->GetName() << std::endl;
}
可见性
可见性其实指的是private
,protected
,public
在类中使用的三种可见性对应如下功能:
- private 指类外不能访问,其子类也不能访问,类内的方法可以访问
- protected 指类外不能访问,其子类的方法可以访问,类内的方法可以访问
- public 指类外能访问,子类能访问,类内的方法可以访问
protected其实涉及继承问题。
#include <iostream>
class Entity {
public:
int x;
void set(int a, int b, int c) {
x = a;
y = b;
z = c;
}
protected:
int y;
private:
int z;
};
class child : public Entity {
public:
void set(int a, int b, int c) {
x = a;
y = b;
//z = c;//不可访问
}
};
int main() {
Entity e;
e.set(1, 2, 3);
child c;
c.x = 2;
c.set(1, 2, 3);
}
在这里面,在child
继承Entity
后,child同样拥有Entity
中的变量y和z
,但是x
消失了(child类中并没有这个变量)
字符字面量
出现形如
const char * name = "12345";
的东西,"12345"
就说一个字符字面量,它会被存储在用户只读的访问区域内,因此形如
char * name = "12345";
name[2] = 'a';
是无效的,未定义的行为。
番外
顺道一提,其实c++的字符串中的每个字符可以是1
,2
,4
个字节,如下图所示
const char * name = u8"wsxk";//utf-8 1 byte
const char16_t * name1 = u"wsxk";//utf-16 2bytes
const char32_t * name2 = U"wsxk";//utf-32 4bytes
const wchar_t * name3 = L"wsxk";//由编译器认定,windows通常是2bytes,linux是4bytes
另外,可以用一个神秘字符,来增加代码可读性:
const char * name = R"(line1
line2
line3
line4)";
//等价
const char * name = "line1\n"
"line2\n"
"line3\n"
"linr4\n";
const
const
只是一个语法上的承诺,你承诺这个变量是个常量,仅此而已
const int *a 表示a指向的地址中的内容不能被修改,可以理解为我把指向内容的int类型声明为const不准修改了,因为const和int在一起
int * const a 表示a指向的地址不能修改,可以理解为这个const和指针名在一起,表示a存储的值(指向的地址)不能改变。
const用在class中的function
#include <iostream>
class Entity {
public:
int x, y;
int getX() const {
return x;
}
};
int main() {
Entity e;
}
这种说明意味着 Entity类中的getX方法承诺不会修改类中的属性
但是如果你在调试的时候想用一下应该怎么办呢?
于是乎出现了mutable
关键字。
#include <iostream>
class Entity {
public:
int x, y;
mutable int m_Debugcount=0;
int getX() const {
m_Debugcount++;
return x;
}
};
int main() {
Entity e;
}
这种用法是可行的。