我最近被咬了(简化)
struct Base {
typedef char T;
};
template<typename T>
struct Foo : Base {
T x[50]; // This is Base::T, not the template parameter
};
Run Code Online (Sandbox Code Playgroud)
换句话说,类成员名称隐藏模板参数(即使来自基类,因此在本地上下文中并不完全明显).
然而,我做了一些实验,发现:
struct Base {
typedef char T;
};
template<typename T, typename B>
struct Foo : B {
T x[50]; // This T is the template parameter,
// even passing Base as B
};
Run Code Online (Sandbox Code Playgroud)
我能想到的唯一出路是给出丑陋的模板参数名称,也意味着在不使用保留名称的情况下安全地编写模板是不可能的(因为模板中使用的类可能会碰撞参数名称...请注意很多C++代码使用uglyfied名称为私人成员).
PS:我没有深入研究这个问题的标准,但g ++和clang ++都同意这个行为,所以我不认为这是一个bug.
PPS:在实际代码中,隐藏的模板参数被命名tid,并且是整数而不是类型.-Wall还没有足够的关于隐藏的问题,我在用valgrind进行了几个小时的调试后发现了它.
最近我注意到,当在类中时,成员函数完全使用相同名称的阴影函数.完全我的意思是,每个具有相同名称的自由函数根本不考虑重载解析.我能理解为什么用这样的事情来完成它:
void f();
struct S
{
void f();
void g()
{
f(); // calls S::f instead of ::f
}
};
Run Code Online (Sandbox Code Playgroud)
在函数具有相同签名的情况下,其唯一自然的变量作用域以相同的方式工作.但是为什么要禁止自由函数具有不同签名的无意义调用:
void f();
struct S
{
void f(int x);
void g()
{
f(); // fails to compile attempting to call S::f, which has wrong signature
}
};
Run Code Online (Sandbox Code Playgroud)
我不是问如何从类中调用一个带阴影的自由函数.我想知道的是这种设计背后的基本原理.
C++标准中有什么东西阻止我重载超类的功能吗?
从这对课开始:
class A { // super class
int x;
public:
void foo (int y) {x = y;} // original definition
};
class B : public A { // derived class
int x2;
public:
void foo (int y, int z) {x2 = y + z;} // overloaded
};
Run Code Online (Sandbox Code Playgroud)
我可以B::foo()轻松打电话:
B b;
b.foo (1, 2); // [1]
Run Code Online (Sandbox Code Playgroud)
但如果我试着打电话A::foo()......
B b;
b.foo (12); // [2]
Run Code Online (Sandbox Code Playgroud)
...我收到编译器错误:
test.cpp: In function 'void bar()':
test.cpp:18: error: no matching function for call …Run Code Online (Sandbox Code Playgroud) 我低于警告.我的部分代码是:
class Base {
public:
virtual void process(int x) {;};
virtual void process(int a,float b) {;};
protected:
int pd;
float pb;
};
class derived: public Base{
public:
void process(int a,float b);
}
void derived::process(int a,float b){
pd=a;
pb=b;
....
}
Run Code Online (Sandbox Code Playgroud)
我收到以下警告:
Warning: overloaded virtual function "Base::process" is only partially overridden in class "derived"
Run Code Online (Sandbox Code Playgroud)
我以任何方式将进程作为虚函数,所以我期待这个警告不应该来......这背后的原因是什么?
考虑一下代码:
class Base {
public:
virtual void gogo(int a){
printf(" Base :: gogo (int) \n");
};
virtual void gogo(int* a){
printf(" Base :: gogo (int*) \n");
};
};
class Derived : public Base{
public:
virtual void gogo(int* a){
printf(" Derived :: gogo (int*) \n");
};
};
int main(){
// 1)
Derived * obj = new Derived ;
obj->gogo(7); // this is illegal because of name hiding
// 2)
Base* obj = new Derived ;
obj->gogo(7); // this …Run Code Online (Sandbox Code Playgroud) 今天进入一个有趣的问题,我试图理解为什么.
考虑以下:
class Base
{
public:
Base(){}
~Base(){}
static void function1(){}
void function2()
{
int function1;
function1 = 0;
function1(); //<-compiler error
function1 = 1;
}
};
Run Code Online (Sandbox Code Playgroud)
我收到以下错误:
表观调用括号前的表达式必须具有(指向 - )函数类型
我想我明白为什么我收到这个错误:
当function1它本身被调用时function2(),它实际上是一个函数指针function1().
里面的范围function2,当int function1被宣布," function1变"阴影" function1函数指针".
当function1()在内部调用时function2(),它假定function1是变量并且给出错误.
通过调用Base::function1();内部来解决这个问题function2().
我的问题是:为什么编译器在声明时没有出错int function1;?这不应该被允许吗?
我有这段代码可以在GCC 9.1中正常工作:
#include <type_traits>
template< typename T >
class A
{
protected:
T value;
public:
template< typename U,
typename...,
typename = std::enable_if_t< std::is_fundamental< U >::value > >
A& operator=(U v)
{
value = v;
return *this;
}
};
template< typename T >
class B : public A<T>
{
public:
using A<T>::operator=;
template< typename U,
typename...,
typename = std::enable_if_t< ! std::is_fundamental< U >::value > >
B& operator=(U v)
{
this->value = v;
return *this;
}
};
int main()
{
B<int> obj; …Run Code Online (Sandbox Code Playgroud) 考虑我有两个纯虚拟类,一个派生自另一个,一个具体类派生自最后一个:
#include <iostream>
#include <string>
class Abstract1
{
public:
virtual ~Abstract1() { };
virtual void method(int a) = 0;
protected:
Abstract1() = default;
};
class Abstract2: public Abstract1
{
public:
virtual ~Abstract2() { };
virtual void method(char c, std::string s) = 0;
protected:
Abstract2() = default;
};
class Concrete : public Abstract2
{
public:
void method(int a) override
{
std::cout << __PRETTY_FUNCTION__ << "a: " << a << std::endl;
}
void method(char c, std::string s) override
{
std::cout << __PRETTY_FUNCTION__ …Run Code Online (Sandbox Code Playgroud) 从这个问题开始:
并考虑这个简化的代码:
#include <string>
#include <iostream>
class Abstract
{
public:
virtual void method(int a)
{
std::cout << __PRETTY_FUNCTION__ << "a: " << a << std::endl;
}
};
class Concrete : public Abstract
{
public:
void method(char c, std::string s)
{
std::cout << __PRETTY_FUNCTION__ << "c: " << c << "; s: " << s << std::endl;
}
};
int main()
{
Concrete c;
c.method(42); // error: no matching function for call to 'Concrete::method(int)'
c.method('a', std::string("S1_1"));
Abstract *ptr = &c; …Run Code Online (Sandbox Code Playgroud) 我想了解下面的代码:
#include<iostream>
using namespace std;
class Base {
public:
virtual void f(float) { cout << "Base::f(float)\n"; }
};
class Derived : public Base {
public:
virtual void f(int) { cout << "Derived::f(int)\n"; }
};
int main() {
Derived *d = new Derived();
Base *b = d;
d->f(3.14F);
b->f(3.14F);
}
Run Code Online (Sandbox Code Playgroud)
这打印
Derived::f(int)
Base::f(float)
Run Code Online (Sandbox Code Playgroud)
我不确定为什么.
第一个调用d-> f(3.14F)调用Derived中的函数f.我不是100%肯定为什么.我看了一下(http://en.cppreference.com/w/cpp/language/implicit_cast),其中说:
浮点类型的prvalue可以转换为任何整数类型的prvalue.小数部分被截断,即,小数部分被丢弃.如果该值不适合目标类型,则行为未定义
对我来说,你不能这样做,因为浮点数不适合int.为什么允许这种隐式转换?
其次,即使我只接受上面的判断,第二次调用b-> f(3.14F)也没有意义.b-> f(3.14F)正在调用虚函数f,因此动态解析它以调用与b指向的对象的动态类型相关联的f(),这是一个Derived对象.因为我们被允许将3.14F转换为int,因为第一个函数调用表明这是合法的,这(我的理解)应该再次调用Derived :: f(int)函数.然而它调用了Base类中的函数.那么为什么呢?
编辑:这是我如何理解并向自己解释的.
b是指向Base对象的指针,因此我们只能使用b来访问Base对象的成员,即使b确实指向某个Derived对象(这是标准的OO /继承内容).
此规则的唯一例外是Base的成员函数声明为virtual.在这种情况下,Derived对象可以覆盖此函数,通过使用完全相同的签名提供另一个实现.如果发生这种情况,那么即使我们碰巧通过指向Base对象的指针访问成员函数,也会在运行时调用此Derived实现.
现在,在上面的代码片段中,我们没有任何重写,因为B :: f和D :: f的签名是不同的(一个是浮点数,另一个是int).因此,当我们调用b-> f(3.14F)时,唯一考虑的函数是原始的B :: f,这就是所谓的.
c++ ×10
name-hiding ×10
name-lookup ×4
overloading ×2
overriding ×2
c++11 ×1
c++14 ×1
declaration ×1
inheritance ×1
pure-virtual ×1
scope ×1
templates ×1
virtual ×1